Code of alan
<?php

    
//////////////////////////////////////////////////////////////////////
    //
    // cards.php - proposed solution to PHP contest at
    //             https://www.php-editors.com/contest_b_1.htm
    //
    // by Alan Krueger (alan_krueger@g1.com) of Group 1 Software
    // written 4/2003
    //
    // For submission, this has been trimmed of diagnostics and alternate
    // search algorithms.  At one point, this was doing both a breadth-
    // first search and a depth-first search.  It first tried the BFS
    // optimistically for part of the timeout period and dropped down to
    // do a DFS (actually an iterative-deepening DFS, since I assume these
    // sequences can be indefinitely long and we don't want it to search
    // forever...)  The DFS has been clipped out because it really only
    // added something to the processing of this when we have a total
    // timeout of around 120s.  In 60s, the BFS seems to work well enough.
    //
    // The BFS is guaranteed to eventually find a solution with the
    // smallest length, since it tries all sequences of increasing length.
    //
    // This uses the optimization that only one "F" is needed (more than
    // once cancel each other out in pairs) and their position appears
    // unimportant.  Thus, we check for a result and compute scores based
    // on both the desired arrangement and its flip.  If it matches the
    // latter, an "F" is tacked onto the current sequence.  Thus, it's
    // possible that there could be a solution of sequence length N and
    // the search will find an N+1 solution first, ending in "F".
    //
    //////////////////////////////////////////////////////////////////////

    
$cards array_reducefile"deck.txt" ), "trimAndAppend""" );
    
$numcards strlen$cards );
    
$half $numcards 2;
    
$maxSeqLength 300;
    
$maxDictSeqLength 1;
    
$desired getDesiredCards$numcards );
    
$desiredFlip myFlip$desired );
        
// apparently, the cut and shuffle operations
        // are invariant over flip, so we don't generate
        // flipped trials, we simply test for either
        // the desired string or the flipped desired string

    
$start time();
    
$totalTimeout ini_get"max_execution_time" );
    if ( 
$totalTimeout <= $totalTimeout 60;
    
$totalTimeout $totalTimeout 5;  // give us some leeway, just in case
    
    // track these to further prune the search space    
    
$identities = array();
    
$flips = array();
    
    
//
    // Breadth-First Search
    //
        
    
$timeout $totalTimeout;
    
$result computeResultBFS$cards );
    
$verified verifyResult$cards$result );
    
    
//
    // Done
    //

    
if ( $result != "" )
        echo 
$result.strlen$result )."\n";
        
    
//echo "verified=".( $verified ? 1 : 0 )." time=".( time() - $start )."\n";
    //echo "iterations=$iterations\n";
        
    
exit( );

    
//////////////////////////////////////////////////////////////////////
    // Functions
    //////////////////////////////////////////////////////////////////////
        
    
function trimAndAppend$current$more )
    {
        return 
$current.trim$more );
    }
    
    function 
computeResultBFS$cards )
    {
        global 
$start$timeout$numcards$half$desired$desiredFlip;
        global 
$identities$flips$iterations$maxSeqLength$maxDictSeqLength;
        
        
$bestScore 0;
        
$bestOps "";
        
        
$origCards $cards;
        
$origCardsFlip myFlip$cards );
        
$current = array();
        
$next = array( $cards => "" );

        
$seen = array();
        
$dictionary = array( "C" => TRUE"S" => TRUE );
        
        
$iterations 0;
        
$iterPerSec 1000;
        
        while ( 
$next != array() )
        {
            
$current $next;
            
$next = array();
            
            foreach ( 
$current as $c => $ops )
            {
                
$opslen strlen$ops );
                ++
$iterations;
                
                if ( 
$iterations $iterPerSec == )
                {
                    
$elapsed time() - $start;
                    
                    
// recompute for better timeout accuracy
                    
if ( $elapsed $timeout )
                        
$iterPerSec $iterations $elapsed;
                    
                    if ( 
$elapsed $timeout )
                        return 
$bestOps;
                }

                if ( isset( 
$seen[$c] ) ) continue; // we've already seen this one
                
$seen[$c] = TRUE;
                
                if ( 
$c == $desired )
                    return 
$ops;
                
                
// see comment above regarding $desiredFlip
                
if ( $c == $desiredFlip )
                    return 
$ops."F";

                
$testScore score$c$desired );
                if ( 
$testScore $bestScore )
                {
                    
$bestScore $testScore;
                    
$bestOps $ops;
                }
                
                
$testScore score$c$desiredFlip );
                if ( 
$testScore $bestScore )
                {
                    
$bestScore $testScore;
                    
$bestOps $ops."F";
                }
                
                
// don't allow ones that end in identity transformations or flips,
                // as these will have already been examined elsewhere
                
if ( hasTailingIdentity$ops ) || hasTailingFlip$ops ) )
                    continue;
                    
                
// don't go beyond the max sequence length
                
if ( $opslen >= $maxSeqLength )
                    continue;

                
// notice features about this set of operations                    
                
if ( $opslen )
                {
                    
// take this time to track identity transformations!
                    
if ( $c == $origCards )
                    {
                        
$identities[$ops] = TRUE;
                    }
                    
// take this time to track flip equivalents!
                    
elseif ( $c == $origCardsFlip )
                    {
                        
$flips[$ops] = TRUE;
                    }
                    
// otherwise, is this an appropriate dictionary entry
                    
elseif ( $opslen && $opslen <= $maxDictSeqLength )
                    {
                        
$dictionary[$ops] = TRUE;
                    }
                }
                
                
// traverse outbound edges of BFS
                
foreach ( array_keys$dictionary ) as $dictOps )
                {
                    
$temp performOps$c$dictOps );
                    
$next[$temp] = $ops.$dictOps;
                }
            }
        }
        
        if ( 
$bestOps == "" && $bestScore )
            
$bestOps "CC";  // apparently doing nothing was best - return a no-op

        
return $bestOps;
    }
    
    function 
hasTailingIdentity$ops )
    {
        global 
$identities;
        
        foreach ( 
array_keys$identities ) as $ident )
        {
            if ( 
stringEndsWith$ops$ident ) )
            {
                return 
TRUE;
            }
        }
        
        return 
FALSE;
    }
    
    function 
addIdentity$ops )
    {
        global 
$identities;
        
$identities[$ops] = TRUE;
    }
    
    function 
hasTailingFlip$ops )
    {
        global 
$flips;
        
        foreach ( 
array_keys$flips ) as $flip )
        {
            if ( 
stringEndsWith$ops$flip ) )
            {
                return 
TRUE;
            }
        }
        
        return 
FALSE;
    }
    
    function 
addFlip$ops )
    {
        global 
$flips;
        
$flips[$ops] = TRUE;
    }
    
    function 
getDesiredCards$len )
    {
        
$ordA ord"A" );
        
$half $len 2;
        
$cards "";
        
        for ( 
$i 0$i $half; ++$i )
        {
            
$cards $cards.chr$ordA $i );
        }
        
        return 
$cards.strtolower$cards );
    }
    
    function 
score$cards$desired )
    {
        global 
$half;
        
$score 0;
        
        foreach ( 
range0$half ) as $i )
        {
            if ( 
$cards[$i] == $desired[$i] )
                ++
$score;
        }
        
        
$score $score 2;

        return 
$score;
    }

    function 
myCut$cards )
    {
        global 
$half;
        return 
substr$cards$half ).substr$cards0$half );
    }

    function 
myFlip$cards )
    {
        return 
strrev$cards );
    }

    function 
myShuffle$cards )
    {
        global 
$half;
        
$out "";

        for ( 
$i 0$i $half; ++$i )
            
$out $out.$cards[$half+$i].$cards[$i];

        return 
$out;
    }
    
    function 
stringEndsWith$string$tail )
    {
        
$taillen strlen$tail );
        
$stringlen strlen$string );
        if ( 
$taillen $stringlen )
            return 
FALSE;
            
        if ( 
$taillen == $stringlen )
            return ( 
strcmp$string$tail ) == );
        
        foreach( 
range1$taillen ) as $i )
        {
            if ( 
$string[$stringlen-$i] != $tail[$taillen-$i] )
                return 
FALSE;
        }
        
        return 
TRUE;
    }

    function 
performOps$cards$ops )
    {
        global 
$numcards$half;

         
$numops strlen$ops );
         
         for ( 
$i 0$i $numops; ++$i )
         {
             
$ch $ops[$i];
             switch ( 
$ch )
             {
                 case 
"S":
                     
$cards myShuffle$cards );
                     break;
                     
                 case 
"C":
                     
$cards myCut$cards );
                     break;
                     
                 case 
"F":
                     
$cards myFlip$cards );
                     break;
                     
                 default:
                     return 
FALSE;
             }
         }
         
         return 
$cards;
     }
         
    function 
verifyResult$cards$ops )
    {
        global 
$numcards$desired;
        
$numcards strlen$cards );
         
         if ( 
$ops != "" )
            
$cards performOps$cards$ops );
            
         return ( 
$cards == $desired );
    }
?>


Back to results


© Copyright 2003-2023 www.php-editors.com. The ultimate PHP Editor and PHP IDE site.