m_reps = array();
		foreach( $reps as $word => $r){
			$this->m_reps[ game_upper( $word)] = $r;
		}
        $this->m_average_reps=0;
        foreach( $reps as $r)
            $this->m_average_reps += $r;
        if( count( $reps))
            $this->m_average_reps /= count( $reps);
		$this->m_input_answers = array();
		foreach( $answers as $word => $answer){
			$this->m_input_answers[ game_upper( $word)] = $answer;
		}		
		
		$this->m_words = array();
			
		$maxlen = 0;
		foreach( $this->m_input_answers as $word => $answer)
		{
			$len = game_strlen( $word);
			if( $len > $maxlen){
				$maxlen = $len;
			}
		}
		
		$N20 = $maxlen;
		if( $N20 < 15)
		    $N20 = 15;
		$this->m_N20min = round( $N20 - $N20/4);
		$this->m_N20max = round( $N20 + $N20/4);
		if( $this->m_N20max > $maxcols and $maxcols > 0){
			$this->m_N20max = $maxcols;
		}
		if( $this->m_N20min > $this->m_N20max){
			$this->m_N20min = $this->m_N20max;
		}
		
		$this->m_words = array();
		foreach( $this->m_input_answers as $word => $answer)
		{
			$len = game_strlen( $word);
			if( $len <= $this->m_N20max){
				$this->m_words[] = game_upper( $word);
			}
		}
    
		$this->randomize();
		    
		return count( $this->m_words);
    }
  
    function randomize()
    {
        $n = count( $this->m_words);
		for($j=0; $j <= $n/4; $j++)
		{
			$i = array_rand( $this->m_words);
			$this->swap( $this->m_words[ $i], $this->m_words[ 0]);
		}
	}
    function computedata( &$crossm, &$crossd, &$letters, $minwords, $maxwords)
    {
        $t1 = time();
    
        $ctries = 0;
        $m_best_score = 0;
        $m_best_connectors = $m_best_filleds = $m_best_spaces = 0;
        $m_best_N20 = 0;
	
        $nochange = 0;
        for(;;)
        {
            //selects the size of the cross
            $N20 = mt_rand( $this->m_N20min, $this->m_N20max);
      
            if( !$this->computenextcross( $N20, $t1, $ctries, $minwords, $maxwords, $nochange))
                break;
                
            $ctries++;
            if (time() - $t1 > $this->m_time_limit - 3){
                break;
            }
            if( $nochange > 10)
                break;
        }
        $this->computepuzzleinfo( $this->m_best_N20, $this->m_best_cross_pos, $this->m_best_cross_dir, $this->m_best_cross_word, false);
    
        //set_time_limit( 30);
    
        return $this->savepuzzle( $crossm, $crossd, $ctries, time()-$t1);
    }
  
	function computenextcross( $N20, $t1, $ctries, $minwords, $maxwords, &$nochange)
	{
        $MAXW = $N20;
    
		$N21 = $N20 + 1;
		$N22 = $N20 + 2;
		$N2222 = $N22 * $N22;
    
		$base_puzzle = str_repeat('0', $N22) .
		str_repeat('0' . str_repeat('.', $N20) . '0', $N20) .
        str_repeat('0', $N22);
		$cross_pos = array();
		$cross_dir = array();
		$cross_word = array();
		$magics = array();
		for ($n = 2; $n < $N21; $n++)
		{
			$a = array();
			for ($r = 2; $r < ($n + 2); $r++)
				$a[] = $r;
			uasort($a, array( $this, 'cmp_magic'));
			$magics[ $n] = $a;
		}
	
		uasort($this->m_words,  array( $this, 'cmp'));
		
		$words = ';' . implode(';', $this->m_words) . ';';
		$puzzle = $base_puzzle;
		$row = mt_rand(3, max( 3, $N20-3));
		$col = mt_rand(3, max( 3, $N20-3));
		$pos = $N22 * $row + $col;
		$poss = array();
		$ret = $this->scan_pos($pos, 'h', true, $puzzle, $words, $magics, $poss, $cross_pos, $cross_dir, $cross_word, $N20);
		
		while ($s = sizeof($poss))
		{
			$p = array_shift($poss);
			if ($this->scan_pos($p[0], $p[1], false, $puzzle, $words, $magics, $poss, $cross_pos, $cross_dir, $cross_word, $N20)){
				$n_words = count( $cross_word);
				if( $maxwords)
				{
					if( $n_words >= $maxwords){
						break;
					}
				}
			}
			if (time() - $t1 > $this->m_time_limit - 3){
				return false;
			}
		}
    $n_words = count( $cross_word);
    if( $minwords)
    {
        if( $n_words < $minwords)
            return true;
    }
    
	$score = $this->computescore( $puzzle, $N20, $N22, $N2222, $n_words, $n_connectors, $n_filleds, $cSpaces, $cross_word);
	if ($score > $this->m_best_score)
	{
		$this->m_best_cross_pos = $cross_pos;
		$this->m_best_cross_dir = $cross_dir;
		$this->m_best_cross_word = $cross_word;
		$this->m_best_puzzle = $puzzle;
		$this->m_bests = array('Words' => "$n_words * 5 = " . ($n_words * 5),
			'Connectors' => "$n_connectors * 3 = " . ($n_connectors * 3),
			'Filled in spaces' => $n_filleds,
			"N20" => $N20
		);
                  
		$this->m_best_score = $score;
		
		$this->m_best_connectors = $n_connectors;
		$this->m_best_filleds = $n_filleds;
		$this->m_best_spaces = $cSpaces;
		$this->m_best_N20 = $N20;      
		$nochange = 0;
	}else
	{
		$nochange++;
	}
	return true;
}
    function computescore( $puzzle, $N20, $N22, $N2222, $n_words, &$n_connectors, &$n_filleds, &$cSpaces, $cross_word)
    {
		$n_connectors = $n_filleds = 0;
		$puzzle00 = str_replace('.', '0', $puzzle);
		$used=0;
		for ($n = 0; $n < $N2222; $n++)
		{
			if ($puzzle00[$n]){
				$used ++;
			    if (($puzzle00[$n - 1] or $puzzle00[$n + 1]) and ($puzzle00[$n - $N22] or $puzzle00[$n + $N22])){
				    $n_connectors++;
			    } else{
				    $n_filleds++;
                }
		    }
        }
        $cSpaces = substr_count( $puzzle, ".");
        $score = ($n_words * 5) + ($n_connectors * 3) + $n_filleds;
        $sum_rep = 0;
        foreach( $cross_word as $word){
            $word = game_substr( $word, 1, -1);        
            if( array_key_exists( $word, $this->m_reps))
                $sum_rep += $this->m_reps[ $word] - $this->m_average_reps;
        }
	    
        return $score-10*$sum_rep;
    }
 
    function computepuzzleinfo( $N20, $cross_pos, $cross_dir, $cross_word, $bPrint=false)
    {
	    $bPrint=false;
        $N22 = $N20 + 2;
        $this->m_mincol = $N22;
        $this->m_maxcol = 0;
        $this->m_minrow = $N22;
        $this->m_maxrow = 0;
        $this->m_cletter = 0;
	
	    if( count( $cross_word) == 0){
		    return;
    	}
		
        if( $bPrint)
          echo "
PuzzleInfo N20=$N20 words=".count($cross_word)."
";
        for($i = 0; $i < count($cross_pos); $i++)
        {
          $pos = $cross_pos[ $i];
          $col = $pos % $N22;
          $row = floor( $pos / $N22);
          $dir = $cross_dir[ $i];
          $len =  game_strlen($cross_word[ $i])-3;
          if( $bPrint)
            echo "col=$col row=$row dir=$dir word=".$cross_word[ $i]."
";
          $this->m_cletter += $len;
          if( $col < $this->m_mincol)
            $this->m_mincol = $col;
          if( $row < $this->m_minrow)
            $this->m_minrow = $row;
          if( $dir == 'h')
            $col += $len;
          else
            $row += $len;
          if( $col > $this->m_maxcol)
            $this->m_maxcol = $col;
          if( $row > $this->m_maxrow)
            $this->m_maxrow = $row;
        }
    
        if( $bPrint)
          echo "mincol={$this->m_mincol} maxcol={$this->m_maxcol} minrow={$this->m_minrow} maxrow={$this->m_maxrow}
";
      
        if( $this->m_mincol > $this->m_maxcol)
          $this->m_mincol = $this->m_maxcol;
        if( $this->m_minrow > $this->m_maxrow)
          $this->m_minrow = $this->m_maxrow;
      }
      function savepuzzle( &$crossm, &$crossd, $ctries, $time)
      {
            $N22 = $this->m_best_N20 + 2;
            $cols = $this->m_maxcol - $this->m_mincol + 1;
            $rows = $this->m_maxrow - $this->m_minrow + 1;
            //if( $cols < $rows)
            //  $bSwapColRow = 1;
            //else
            $bSwapColRow = 0;
            if( $bSwapColRow)
            {
                Swap( $cols, $rows);
                Swap( $this->m_mincol, $this->m_minrow);
                Swap( $this->m_maxcol, $this->m_maxrow);
            }
	
	        $crossm = new stdClass();
            $crossm->datebegin = time();
            $crossm->time = $time;
            $crossm->cols = $cols;
            $crossm->rows = $rows;
            $crossm->words = count( $this->m_best_cross_pos);
            $crossm->wordsall = count( $this->m_input_answers);
            $crossm->createscore = $this->m_best_score;
            $crossm->createtries = $ctries;
            $crossm->createtimelimit = $this->m_time_limit;
            $crossm->createconnectors = $this->m_best_connectors;
            $crossm->createfilleds = $this->m_best_filleds;
            $crossm->createspaces = $this->m_best_spaces;
	
            for($i = 0; $i < count($this->m_best_cross_pos); $i++)
            {
                $pos = $this->m_best_cross_pos[ $i];
                $col = $pos % $N22;
                $row = floor( ($pos-$col) / $N22);
                $col += - $this->m_mincol + 1;
                $row += - $this->m_minrow + 1;
                $dir = $this->m_best_cross_dir[ $i];
                $word = $this->m_best_cross_word[ $i];
                $word = substr( $word, 1, strlen( $word)-2);
                $rec = new stdClass();
      
                $rec->col = $col;
                $rec->row = $row;
                $rec->horizontal = ($dir == "h" ? 1 : 0);
      
                $rec->answertext = $word;
                $rec->questiontext = $this->m_input_answers[ $word];
		
                if( $rec->horizontal)
                    $key = sprintf( 'h%10d %10d', $rec->row, $rec->col);
                else
                    $key = sprintf( 'v%10d %10d', $rec->col, $rec->row);
		
                $crossd[ $key] = $rec;
            }
            if( count( $crossd) > 1){
		        ksort( $crossd);
	        }
	
            return (count( $crossd) > 0);
    }
	function swap( &$a, &$b)
	{
		$temp = $a;
		$a = $b;
		$b = $temp;
	}
	function displaycross($puzzle, $N20) 
    {
		$N21 = $N20 + 1;
		$N22 = $N20 + 2;
		$N2222 = $N22 * $N22;
		$N2221 = $N2222  - 1;
		$N2200 = $N2222 - $N22;
    
		$ret = "
| "; } elseif ( $c == '0') { $ret .= " | "; } elseif ($c == '.') { $ret .= " | "; } else { if ((game_substr( $puzzle, $n - 1, 1) > '0' or game_substr( $puzzle, $n + 1, 1) > '0') and (game_substr( $puzzle, $n - $N22, 1) > '0' or game_substr( $puzzle, $n + $N22, 1) > '0')) { $ret .= " | $c"; } else { $ret .= " | $c"; } } if ($n == $N2221) { return "$ret |