  var DOWN = 0;
  var ACROSS = 1;
  var CANT_GO_DOWN = '|';
  var CANT_GO_ACROSS = '_';
  var CANT_GO_DOWN_OR_ACROSS = '+';
  var BLANK = '@';
  var ENTER_KEY = 13 ;
  var curWordNumber = -1;


   function isBlank( ch ) 
   {
       return ch == BLANK || ch == CANT_GO_DOWN || ch == CANT_GO_ACROSS || ch == CANT_GO_DOWN_OR_ACROSS ;
   }
   
   
   function getAnsChar( row, col )
   {
       if ( row < 0 || row >= puzzle.numRows || col < 0 || col >= puzzle.numColumns ) {
           return BLANK ;
       }
       return puzzle.answer.get( row, col );
   }
   
   function writePuzzle( puzzle )
   {
      var row;
      var col;
      
      document.write( '<table class="puzzleTable">' );
      for ( row = -1; row<=puzzle.numRows; row++ ) {
          document.write( "<tr>" );
          for ( col = -1; col<=puzzle.numColumns; col++ ) {
              var ansChar = getAnsChar( row, col );
              if ( isBlank( ansChar ) ) {
                    if ( row==-1 || row==puzzle.numRows || col == -1 || col == puzzle.numColumns ) {
	              document.write( "<td class='blank0'>&nbsp;</td>" );
                    }
                    else {
	              document.write( "<td class='blank'>&nbsp;</td>" );
                    }
              }
              else {
	              document.write( "<td onclick='clickSquare(" + row + "," + col +")' id='sq" + col + "_" + row + "' class='sq'>" );
	              document.write(   "<div class='block'>" );
		          document.write(     "<div class='cwnum' id='num" + col + "_" + row + "'></div>" );
                  document.write(     "<div class='cwlet' id='let" + col + "_" + row + "'>" );
	              //document.write(      ansChar );
                  document.write(      "</div>" );
                  document.write(   "</div>" );
	              document.write( "</td>" );
              }
          }
          document.write( "</tr>" );
      }
      document.write( "</table>" );
      
      document.write( "<div style=' height:30px'><span id='clueInfoNum'></span>&nbsp;<span id='clueInfo'></span></div>" );
      document.write( "<div style=' height:30px'><span style='width:90px;'>" + txtAnswer + "</span>" );
      document.write( "<span id='guessDiv' style='display: none'>" );
      document.write(    "<input class='inputUpper' id='guessInput' onkeyup='inputChanged(event)' onchange='guessChanged()' />" );
      document.write(    "&nbsp;<button id='enterButton' onclick='enterGuess()'>" + txtEnter + "</button>" );
      document.write( "</span></div>" );
      document.write( "<hr />" );
      
      document.write( "<button id='showAnswer' onclick='showSolution( puzzle )'>" + txtShowAnswer + "</button>&nbsp;" );
      document.write( "<button id='checkAnswers' onclick='checkAnswers( puzzle )'>" + txtCheck + "</button>" );
      
      initElementVars();
   }
   
   
   
   function clickClue( pwNum )
   {
      var puzzleWord = puzzle.placedWords[ pwNum ];
      hilightNewWord( puzzleWord );
      curWordNumber = pwNum ;
   }
   
   function clickSquare( row, col)
   {
      uncheckAnswers( puzzle ) ;
      var puzzleWord = null ;
      
      puzzleWord = puzzle.findWordAt( row, col, ACROSS );
      
      if ( puzzleWord == null || currentHilightedWord == puzzleWord ) {
      
           puzzleWord = puzzle.findWordAt( row, col, DOWN );
           if ( puzzleWord == currentHilightedWord ) {
                 puzzleWord = null ;
           }
       }    
       hilightNewWord( puzzleWord );
   }

   function Puzzle_findWordAt( row, col, direction ) 
   {
       var i ;
       var puzzleWord ;
       for ( i=0; i<this.placedWords.length; i++ ) {
           puzzleWord = this.placedWords[i] ;
           
           if ( puzzleWord.direction == direction ) {
                if ( direction == ACROSS ) {
                    if ( row == puzzleWord.row ) {
                        if ( col >= puzzleWord.col && col<(puzzleWord.col + puzzleWord.word.length) ) {
                             curWordNumber = i;
                             return puzzleWord ;
                        }
                    }
                }
                else {
                    if ( col == puzzleWord.col ) {
                         if ( row >= puzzleWord.row && row < (puzzleWord.row + puzzleWord.word.length) ) {
                              curWordNumber = i;
                              return puzzleWord ;
                         }
                    }
                }
                
           }
       }
       return null ;
   }

   function doNothing()
   {
   }
   
   function writeClues( puzzle ) 
   {
       var i ;
	   var direction = -1 ;
       document.write( "<table id='clues'>" );
       for ( i=0; i<puzzle.placedWords.length; i++ ) {
           var w = puzzle.placedWords[i];
           if ( direction != w.direction ) {
                direction = w.direction ;
           	    document.write( "<tr><td colspan='2'><b>" + ((direction == DOWN) ? txtDown : ("<br/>" + txtAcross )) + "</b></td></tr>" );
           }
           document.write( "<tr>" );
           document.write(    "<td valign='top' onclick='clickClue(" + i + ")' align='right'><a href='javascript:doNothing()' id='clueNum" + w.direction + "-" + w.clueNumber + "' class='clue'>" + w.clueNumber + "</a></td>" );
           document.write(    "<td onclick='clickClue(" + i + ")'><a href='javascript:doNothing()' id='clue" + w.direction + "-" + w.clueNumber + "' class='clue'>" + w.clue + "</a></td>" );
           document.write( "</tr>" );
       }
       document.write( "</table>" );
   }

   function getLetterElement( row, col ) 
   {
       return letterFields[row][col];
       //return document.getElementById( "let" + col + "_" + row );
   }
   
    function getSquareElement( row, col )
    {
        return squareFields[row][col]; 
    }
   
   
   function showLetter( col, row, ch )
   {
       var letterField = getLetterElement( row, col );
       letterField.innerHTML = ch ;
   }
   
  function showNumber( row, col, clueNumber )
  {
       var numberField = document.getElementById( "num" + col + "_" + row );
       numberField.innerHTML = clueNumber ;
  }
   

   function showSolution( puzzle )
   {
      checkAnswers( puzzle );
      var row;
      var col;

      for ( row = 0; row<puzzle.numRows; row++ ) {
          for ( col = 0; col<puzzle.numColumns; col++ ) {
              var ansChar = puzzle.answer.get( row, col );
              if (!isBlank( ansChar ) ) {
                  showLetter( col, row, ansChar );
              }
          }
      }
   }

   var numWrong = 0;
   
   function checkAnswers( puzzle ) 
   {
      hilightNewWord( null ) ;
      var row;
      var col;

      numWrong = 0;
      for ( row = 0; row<puzzle.numRows; row++ ) {
          for ( col = 0; col<puzzle.numColumns; col++ ) {
              var ansChar = puzzle.answer.get( row, col );
              if (!isBlank( ansChar ) ) {
			       var letterField = getLetterElement( row, col );
			       var guessedChar = letterField.innerHTML ;
			       if ( guessedChar != ansChar ) {
			      	   letterField.className = 'wrongLet' ; 
			      	   numWrong++;
			       }
              }
          }
      }
   }


   function isDone( puzzle ) 
   {
      var row;
      var col;

      for ( row = 0; row<puzzle.numRows; row++ ) {
          for ( col = 0; col<puzzle.numColumns; col++ ) {
              var ansChar = puzzle.answer.get( row, col );
              if (!isBlank( ansChar ) ) {
			       var letterField = getLetterElement( row, col );
			       var guessedChar = letterField.innerHTML ;
			       if ( guessedChar != ansChar ) {
			      	   return false ;
			       }
              }
          }
      }
      return true ;
   }
   
   
   function uncheckAnswers( puzzle )
   {
      if ( numWrong != 0 ) {
	      var row;
	      var col;
	
	      for ( row = 0; row<puzzle.numRows; row++ ) {
	          for ( col = 0; col<puzzle.numColumns; col++ ) {
	              var ansChar = puzzle.answer.get( row, col );
	              if (!isBlank( ansChar ) ) {
				      var letterField = getLetterElement( row, col );
	  	      	      letterField.className = 'cwlet' ; 
	              }
	          }
	      }
	      numWrong = 0;
	  }
   }
   

   function Array2d( numRows, numColumns )
   {
      var row;
      var col;
      this.data = new Array();

      for ( row = 0; row<numRows; row++ ) {
         var dataArray = new Array();
         for ( col = 0; col<numColumns; col++ ) {
             dataArray[ col ] = BLANK;
         }
         this.data[ row ] = dataArray ;
      }       
      this.get = Array2d_get ;
      this.set = Array2d_set ;
      this.addWord = Array2d_addWord ;
   }


   function Array2d_get( row, col )
   {
       return this.data[row][col] ;
   }

   function Array2d_set( row, col, val )
   {
      this.data[row][col] = val ;
   }

   function Array2d_addWord( word, x, y, direction )
   {
      var i;
      for ( i=0; i<word.length; i++ ) {
         var ch = word.charAt( i ) ;
         this.set( y, x, ch );
         if ( direction == DOWN ) {
            y++;
         }
         else {
            x++ ;
         }
      }
   }



   function PuzzleWord( word, clue, row, col, direction )
   {
      this.word = word ;
      this.clue = clue ;
      this.row = row ;
      this.col = col ;
      this.direction = direction ;
      this.clueNumber = 0;
      
      this.compareTo = PuzzleWord_compareTo ;
   }
   
   /**
      Compare this PuzzleWord with otherWord to determine
      how they should be sorted.
   **/
   function PuzzleWord_compareTo( otherWord )
   {
	  if ( otherWord.direction != this.direction ) {
	      //return this.direction - otherWord.direction ;
	      return otherWord.direction - this.direction ;
	  }
	  
      if ( this.row != otherWord.row ) {
          return this.row - otherWord.row ;
      }
      else {
          // on the same row, compare columns
          return this.col - otherWord.col ;
      }
   }


   var currentHilightedWord = null ;
   
   function hilightNewWord( puzzleWord )
   {
      enableEnterButton( false );
      if ( currentHilightedWord != null ) {
          hilightWord( currentHilightedWord, false );
      }
      if ( puzzleWord != null ) {
          hilightWord( puzzleWord, true );
      }
      currentHilightedWord = puzzleWord ;
      updateInputArea( puzzleWord );
   }
   
   
   var inputLength ;
   
   var clueInfoNum ;
   var clueInfo ;
   var guessDiv ;
   var guessInput;
   var enterButton;
   var letterFields ;
   var squareFields ;

  function initElementVars()
  {
      clueInfoNum = document.getElementById( 'clueInfoNum' );
   	  clueInfo = document.getElementById( 'clueInfo' );
   	  guessDiv = document.getElementById( 'guessDiv' );
	  guessInput = document.getElementById( 'guessInput' );
	  guessInput = document.getElementById( 'guessInput' );
	  guessInput = document.getElementById( 'guessInput' );
      enterButton = document.getElementById( 'enterButton' );
      
      var row;
      var col;
      
      letterFields = new Array();
      squareFields = new Array();
      for ( row = 0; row<puzzle.numRows; row++ ) {
          letterFields[row] = new Array();
          squareFields[row] = new Array();
          for ( col = 0; col<puzzle.numColumns; col++ ) {
              letterFields[row][col] = document.getElementById( "let" + col + "_" + row );
              squareFields[row][col] = document.getElementById( "sq"  + col + "_" + row );
          }
      }
  }
   
   function updateInputArea( puzzleWord )
   {
	  
   	  if ( puzzleWord != null ) {
   	      clueInfoNum.innerHTML = puzzleWord.clueNumber + " " +
   	                 ( (puzzleWord.direction == DOWN) ? txtDown : txtAcross ) + ":";
	   	  clueInfo.innerHTML = puzzleWord.clue ;
          guessDiv.style.display='inline';
          guessInput.value = "" ;
   	      inputLength = puzzleWord.word.length ;
          guessInput.size = inputLength ;
          guessInput.maxLength = inputLength ;
          guessInput.focus();
   	  }
   	  else {
   	      clueInfoNum.innerHTML = "&nbsp;" ;
   	  	  clueInfo.innerHTML = "&nbsp;" ;
          guessDiv.style.display='none';
   	  }
   }
   
   
   var lastKey = null ;
   var lastKeyCtrl = null ;
   
   function guessChanged()
   {
      // only enable Enter button if exactly the 
      // right number of characters have been entered.
      
	  var guessLength = guessInput.value.length ;
      enableEnterButton(  guessLength == inputLength );
      if ( lastKey == ENTER_KEY ) {
          if ( guessLength == inputLength ) {
              enterGuess();
          }
          else if ( guessLength == 0 ) {
			  var nextWord ;              
              if ( lastKeyCtrl ) {
				 nextWord = curWordNumber - 1;
				 if ( nextWord < 0 ) {
				      nextWord = puzzle.placedWords.length - 1;
				 }                                    
              }
              else {
                  nextWord = (curWordNumber + 1) % puzzle.placedWords.length ;
              }
              clickClue( nextWord ) ;
               
          }
      }
   }
   
   
   function inputChanged(curEvent)
   {
      if ( !curEvent ) {
          curEvent = window.event ;
      }
   
      lastKey = curEvent.keyCode ;
      lastKeyCtrl = curEvent.ctrlKey ;
      // wait a fraction of a second so that the input field's value gets updated
      // then check to see if the write number of characters have been entered.
      setTimeout( 'guessChanged()', 100 );
   }

   function enableEnterButton( enable )
   {
      enterButton.disabled = !enable;
   }
      
   function enterGuess()
   {
      enableEnterButton( false );
      var guessedValue = guessInput.value.toUpperCase(); ;   
      var i ;
      var col = currentHilightedWord.col ;
      var row = currentHilightedWord.row ;
      
      for ( i=0; i<guessedValue.length ; i++ ) {
          var guessedChar = guessedValue.charAt( i );
          showLetter( col, row, guessedChar );
          if ( currentHilightedWord.direction == DOWN ) {
              row ++ ;
          }
          else {
              col ++ ;
          }    
      }
      guessInput.value = "" ;
      if ( isDone( puzzle ) ) {
           alert( 'good job' );
      }
   }
   
   function hilightWord( puzzleWord, hilight )
   {
   
        var row = puzzleWord.row ;
        var col = puzzleWord.col ;
        var i ;
        var length = puzzleWord.word.length
        
        for ( i=0; i<length; i++ ) {
        
            var squareField = getSquareElement( row, col );
            squareField.className = (hilight ? "hilightSq" : "sq") ;
        
            if ( puzzleWord.direction == DOWN ) {
                row++;
            }
            else {
                col++;
            }
        }
        
        hilightClue( puzzleWord, hilight );
        
   }
   
   function hilightClue( puzzleWord, hilight )
   {
	   var id = "clue" + puzzleWord.direction + "-" + puzzleWord.clueNumber ;
	   var clueField = document.getElementById( id );
	   clueField.className = hilight ? "hilightClue" : "clue" ;

	   id = "clueNum" + puzzleWord.direction + "-" + puzzleWord.clueNumber ;
	   clueField = document.getElementById( id );
	   clueField.className = hilight ? "hilightClue" : "clue" ;
   }
   
    
   function Puzzle( numRows, numColumns )
   {
      this.numRows = numRows ;
      this.numColumns = numColumns ;
      this.answer = new Array2d( numRows, numColumns );
      this.guess = new Array2d( numRows, numColumns );
      this.placedWords = new Array();
      this.unplacedWords = new Array();
      this.numUnplacedWords = 0;
      
      this.placeWord = Puzzle_placeWord ;
      this.placeWords = Puzzle_placeWords ;
      this.placeWordAnywhere = Puzzle_placeWordAnywhere ;
      this.wordFits = Puzzle_wordFits ;
      this.markSpace = Puzzle_markSpace ;
      this.isBlank = Puzzle_isBlank ;
      this.assignClueNumbers = Puzzle_assignClueNumbers ;
      this.findWordAt = Puzzle_findWordAt ;
      this.addWord = Puzzle_addWord;
      this.removeWord = Puzzle_removeWord ;
  }


  /**
     Adds a word and its clue to the puzzle at the 
     specified location and direction.
  **/
  function Puzzle_placeWord( word, clue, x, y, direction )
  {
        this.placedWords[ this.placedWords.length ] = new PuzzleWord( word, clue, y, x, direction );
        defaultStatus = this.placedWords.length + " words loaded." ;
        
        this.answer.addWord( word, x, y, direction );
        
        if ( direction == DOWN ) {
             this.markSpace( y-1, x, CANT_GO_DOWN_OR_ACROSS );
             this.markSpace( y + word.length, x, CANT_GO_DOWN_OR_ACROSS );
        }      
        else {
             this.markSpace( y, x-1, CANT_GO_DOWN_OR_ACROSS );
             this.markSpace( y, x+word.length, CANT_GO_DOWN_OR_ACROSS );
        }
        
        for ( i=0; i<word.length; i++ ) {
            if ( direction == DOWN ) {
                this.markSpace( y, x-1, CANT_GO_DOWN );
                this.markSpace( y, x+1, CANT_GO_DOWN );
                y++;
            }
            else {
                this.markSpace( y-1, x, CANT_GO_ACROSS );
                this.markSpace( y+1, x, CANT_GO_ACROSS );
                x++ ;
            }
        }
  }
  
  
  /**
     Sort the placedWords array so that the words are in the order
     that their clues should be presented.
  **/
  
  function sortArray( anArray )
  {
      var i,j;
      var listSizeMin1 = anArray.length - 1;
      
      for ( i=0; i<=listSizeMin1; i++ ) { 
          for (j=0; j<listSizeMin1-i; j++) {

               var aWord = anArray[j];
               var bWord = anArray[ j + 1 ];

               if ( aWord.compareTo( bWord ) > 0 ) {         
                   // swap words in array
                   anArray[j] = bWord ;
                   anArray[ j + 1 ] = aWord ;
             }
         }
      }
  }
  
  function Puzzle_assignClueNumbers()
  {
      var row;
      var col ;
      var clueNumber = 0;
      var pWord ;
      for ( row = 0; row<puzzle.numRows; row++ ) {
          for ( col = 0; col<puzzle.numColumns; col++ ) {
               var foundWordHere = false ;
               for ( pWord=0; pWord<this.placedWords.length; pWord++ ) {
                    var placedWord = this.placedWords[pWord] ;
                    if ( placedWord.row == row && placedWord.col == col ) {
                        if ( ! foundWordHere ) {
                             foundWordHere = true ;
                             clueNumber ++ ;
                             showNumber( row, col, clueNumber );
                        }
                        placedWord.clueNumber = clueNumber ;
                    }
               }
          }
      }
  }
  
  
  function Puzzle_markSpace( y, x, markAs )
  {
      if ( x >= 0 && x<this.numColumns && y>=0 && y<this.numRows ) {
          var curVal = this.answer.get( y, x );
          if ( (markAs == CANT_GO_DOWN && curVal == CANT_GO_ACROSS ) ||
               ( markAs == CANT_GO_ACROSS && curVal == CANT_GO_DOWN ) ) {
               this.answer.set( y, x, CANT_GO_DOWN_OR_ACROSS );
          }
          else if ( curVal == BLANK ) {
               this.answer.set( y, x, markAs );
          }
      }
  }
  
  function Puzzle_isBlank( y, x ) 
  {
      if ( x >= 0 && x<this.numColumns && y>=0 && y<this.numRows ) {
          var curVal = this.answer.get( y, x );
          return isBlank( curVal );          
      }
      else {
          return true ;
      }
  }
  


  
  /**
     Search for a place where this word fits on the puzzle.
     If it finds a place the word is added to the puzzle.
     If the word would fit in multiple places, it places the word
     in the position where the most letters are shared with 
     existing words.
  **/
  function Puzzle_placeWordAnywhere( word, clue ) 
  {
     word = word.toUpperCase();
      var wordLen = word.length ;
      var random2 = Math.floor( Math.random()* 2) ;
      var d ;
      var mostMatchingLetters = -1 ;
      var bestX;
      var bestY;
      var bestDirection ;
      var maxStartY ;
      var maxStartX ;
      
      for ( d=0; d<2; d++ ) {
          var direction = (d + random2) % 2;
          if ( direction == DOWN ) {
              maxStartY = this.numRows - wordLen ;
              maxStartX = this.numColumns - 1;
          }
          else {
              maxStartX = this.numColumns - wordLen ;
              maxStartY = this.numRows - 1;
          }
//          alert( 'maxStartX=' + maxStartX + '   maxStartY=' + maxStartY );
          var randomX = Math.floor( Math.random() * maxStartX );
          var randomY = Math.floor( Math.random() * maxStartY );
          for ( startX = 0 ; startX<=maxStartX; startX++ ) {
              for ( startY = 0; startY<=maxStartY; startY++ ) {
                   var x = (startX + randomX) % (maxStartX + 1);
                   var y = (startY + randomY) % (maxStartY + 1);
                   
                   // try to see if word will fit going direction 
                   // starting at x, y
                   var matchingLetters = this.wordFits( word, x, y, direction );
                   if ( (matchingLetters > mostMatchingLetters) && (matchingLetters < wordLen) ) {
//                       alert( word + ' fits at ' + x + ',' + y + ' matchingLetters=' + matchingLetters );
                       mostMatchingLetters = matchingLetters ;
                       bestX = x ;
                       bestY = y ;
                       bestDirection = direction ;
                   }
              }
          }
      }
      
      if ( mostMatchingLetters > 0 ) {
//           alert( 'word fits at row ' + bestY + " col " + bestX + " going " + ((bestDirection == DOWN) ? "down" : "across") + " " + mostMatchingLetters );
           this.placeWord( word, clue, bestX, bestY, bestDirection );
           return true ;
      }
      
      // didn't place word
      return false ;
  }


  function Puzzle_wordFits( word, startX, startY, direction ) 
  {
      var wordLen = word.length ;
      var i;
      var x=startX ;
      var y=startY ;
      var matchingLetters = 0;
      
      if ( direction == DOWN ) {
          if ( !this.isBlank( startY-1, startX ) ) return 0;
          if ( !this.isBlank( startY + wordLen, startX )) return 0;
      }
      else {
          if ( !this.isBlank( startY, startX - 1 ) ) return 0;
          if ( !this.isBlank( startY, startX + wordLen ) ) return 0;
      }

      for ( i=0; i<wordLen; i++ ) {
          var letter = word.charAt( i );
          //defaultStatus = "wordFits: word=" + word + " startX=" + startX + " startY=" + startY + " direction=" + direction + " i=" + i + " x=" + x + " y=" + y ;
          var puzzleChar = this.answer.get( y, x );
          if ( puzzleChar == letter ) {
              matchingLetters ++ ;
          }
          else if ( ! ( (puzzleChar == BLANK)   ||
                        ((direction == DOWN) && (puzzleChar == CANT_GO_ACROSS)) ||
                        ((direction == ACROSS) && (puzzleChar == CANT_GO_DOWN)) ) ) {
                 return -1 ;
 	      }
	      if ( direction == DOWN ) {
	          y++;
	      }
	      else {
	          x++;
	      }
      }
      return matchingLetters ;
  }



  function WordCluePair( word, clue )
  {
       this.word = word ;
       this.clue = clue ;
       this.compareTo = WordCluePair_compareTo ;
  }
  
  function WordCluePair_compareTo( wordClue )
  {
      return this.word.length - wordClue.word.length ;
  }
  
  /**
     addWord adds the word and clue to a list of word/clue pairs that may be used 
     for this puzzle.
  **/
  function Puzzle_addWord( word, clue ) 
  {
    if ( word.length > this.numColumns && word.length > this.numRows ) {
       return false ;
    }
    word = word.toUpperCase() ;
    var i;
    for ( i=0; i<this.numUnplacedWords; i++ ) {
        if ( this.unplacedWords[ i ].word == word ) {
            // word already in list
            return false ;
        }
    }
	this.unplacedWords[ this.numUnplacedWords ] = new WordCluePair( word, clue );
	this.numUnplacedWords ++ ;
	return true ;
  }
  
  function Puzzle_removeWord( index )
  {
     var unplacedWord = this.unplacedWords[ index ];
     this.numUnplacedWords -- ;
     if ( this.numUnplacedWords > 0 ) {
         this.unplacedWords[ index ] = this.unplacedWords[ this.numUnplacedWords ] ;
     }
     return unplacedWord ;
  }

      

  function Puzzle_placeWords()
  {
      sortArray( this.unplacedWords );
//      alert( "num unplaced = " + this.numUnplacedWords );
	  if ( this.placedWords.length == 0 ) {
	      // no words placed yet.   pick one at random
		  var randomIndex = Math.floor( Math.random() * this.numUnplacedWords/2 + this.numUnplacedWords / 2 )  ;
          var wordClue = this.removeWord( randomIndex );
          var row = Math.floor(this.numRows / 2) ;
          var col = Math.floor( (this.numColumns - wordClue.word.length) / 2 ); 
          this.placeWord( wordClue.word, wordClue.clue, col, row, ACROSS );
	  }       
	  
	  // try to place each word anywhere
	  do {
		  var i;
		  var wordsPlaced = 0;
		  // try to start with one of the words in the longer half
		  var randomStart = Math.floor( Math.random() * this.numUnplacedWords/2 + this.numUnplacedWords / 2 )  ;
		  for ( i=0; i<this.numUnplacedWords; i++ ) {
		       var wordIndex = (i + randomStart) % this.numUnplacedWords ;
		       var wordClue = this.unplacedWords[i];
//		       alert( 'trying to place ' + wordClue.word );
		       if ( this.placeWordAnywhere( wordClue.word, wordClue.clue ) ) {
//	  	           alert( "placeWordAnywere " + wordClue.word + " returned true." );
		           wordsPlaced++;
		           this.removeWord( i );
		           break;
		       }
		  }
		  // as long as we place at least one new word, repeat and try again.
	  } while ( wordsPlaced > 0 );
  }
  
  function writePuzzleAndClues( puzzle )
  {
    sortArray( puzzle.placedWords );;
    document.write( "<table><tr><td width='504px'>" );
    writePuzzle( puzzle );
    document.write( "</td><td valign='top'>" );
    puzzle.assignClueNumbers();
    writeClues( puzzle );
    document.write( "</td></tr></table>" );
  }
 
