Code of matteo
<?php
/*********************************************************/
/* Jumbled Words for PHP-Editors.com Coding Contest */
/* (C) 2003 Matteo Beccati <matteo@beccati.com> */
/*********************************************************/
$solveTimeLimit = ini_get('max_execution_time');
if (!$solveTimeLimit) $solveTimeLimit = 10000;
$solveMaxTime = time() - 3;
echo "<pre>\n";
parseFile();
$result = 0;
while (list($x, ) = each($entries))
{
$sol[$x] = array();
$result += solveEntry($entries[$x], $sol[$x]);
}
for ($x=0; isset($sol[$x]); $x++)
echo join(' ', $sol[$x])."\n";
echo $result."\n";
echo "</pre>";
/***************************************************/
/* Parse input file */
/***************************************************/
function parseFile()
{
global $entries, $solveTimeLimit, $solveMaxTime, $solveMd5;
$buf = file('lists.txt');
$e = 0;
$c = count($buf);
// Read words
for ($x = 0; $x < $c; $x++)
{
$s = trim($buf[$x]);
$last = substr($s, -1);
if ($last == ',')
{
// List found
$entries[$e][0] = explode(' ', substr($s, 0, strlen($s)-1));
$entries[$e][1] = '';
// Set entry max score as the length of all the words
$entries[$e]['maxscore'] = strlen(join($entries[$e][0]));
}
else
{
// (Part of) Sentence found
if (!isset($entries[$e][1])) $entries[$e][1] = '';
$entries[$e][1] .= str_replace(' ', '', $last == '.' ? substr($s, 0, strlen($s)-1) : $s);
if ($last == '.')
// Last sentence line
$e++;
}
}
$total_score = 0;
for ($x = 0; isset($entries[$x][0]); $x++)
{
$tmp = join('', $entries[$x][0]);
// Calculate md5 of list and sentence to find duplicates (who knows? :)
$entries[$x]['md5'] = md5($tmp.$entries[$x][1]);
// Calculate max theoric score for the pair
if (isset($solveMd5[$entries[$x]['md5']]))
// Pair already present, fake a null max score because only one would be evaluated
$entries[$x]['maxscore'] = 0;
else
{
$solveMd5[$entries[$x]['md5']] = true;
$jlen = strlen($entries[$x][1])+2;
$lasting = strlen(removeLetters(wordSort($entries[$x][1]), wordSort($tmp)));
$lasting = $lasting <= 2 ? 0 : $lasting - 2;
$e2 = $entries[$x]['maxscore'] - $lasting;
$entries[$x]['maxscore'] = min($jlen, $e2);
$total_score += $entries[$x]['maxscore'];
}
}
// Calculate available time for each entry
for ($x = 0; isset($entries[$x][0]); $x++)
{
$entries[$x]['timespan'] = floor($solveTimeLimit * $entries[$x]['maxscore'] / $total_score);
if (!$entries[$x]['timespan'] && $entries[$x]['maxscore'])
{
$entries[$x]['timespan'] = 1;
$solveMaxTime--;
}
}
if (isset($entries[$x])) unset($entries[$x]);
// Sort entries by score, highest first
uasort($entries, "entries_sort_callback");
}
/***************************************************/
/* Sort letters in a word */
/***************************************************/
function wordSort($w)
{
$a = array();
$len = strlen($w);
for ($x=0; $x<$len; $x++)
$a[] = $w{$x};
sort($a);
return join('', $a);
}
/***************************************************/
/* Highlight bonus letters */
/***************************************************/
function highLight($w)
{
for ($i = 0; $i < strlen($w[1]);$i++)
{
$c = $w[1]{$i};
$x = strrpos($w[0], $c);
$w[0] = substr($w[0], 0, $x).'{'.$c.'}'.substr($w[0], $x+1);
}
$w[0] = str_replace('}{', '', $w[0]);
$w[0] = str_replace('{', '<span style="color: red">', $w[0]);
$w[0] = str_replace('}', '</span>', $w[0]);
return $w[0];
}
/***************************************************/
/* Removes needle letters from haystack */
/***************************************************/
function removeLetters($needle, $haystack)
{
while ($haystack !== '' && $needle !== '')
{
if (($x = strpos($haystack, $needle{0})) !== false)
{
$haystack = substr($haystack, 0, $x).substr($haystack, $x+1);
$needle = substr($needle, 1);
}
else
$needle = str_replace($needle{0}, '', $needle);
}
return $haystack;
}
/***************************************************/
/* Solve one entry */
/***************************************************/
function solveEntry($e, &$sol)
{
global $solveEntryBuffer, $solveMaxScore, $solveStop, $solveMaxTime, $solveMd5;
if (is_array($solveMd5[$e['md5']]))
{
$sol = $solveMd5[$e['md5']][0];
return $solveMd5[$e['md5']][1];
}
$solveMaxScore = $e['maxscore'];
foreach ($e[0] as $k => $v)
{
$solveMaxScore += strlen($v);
$e2[0][$k] = wordSort($v);
}
uasort($e2[0], 'strlen_callback');
$e2[1] = wordSort($e[1]);
$solveMaxScore = $e['maxscore'];
$solveStop = false;
$solveMaxTime += $e['timespan'];
$solveEntryBuffer = $e2[0];
$solve = new solver($e2[1]);
$score = $solve->score;
$words = array();
while (isset($solve->best) && isset($solve->children[$solve->best]))
{
$words[] = array($e[0][$solve->best], $solve->children[$solve->best]->blank);
$solve = $solve->children[$solve->best];
}
$blanks = '';
foreach ($words as $k => $v)
{
if (strlen($blanks))
{
$tmp = $blanks;
$blanks = $v[1];
$words[$k][1] = str_replace($tmp, '', $v[1]);
}
elseif (strlen($v[1]))
$blanks = $v[1];
}
usort($words, 'sol_compare_callback');
foreach ($words as $v)
$sol[] = highLight($v);
$solveMd5[$e['md5']] = array($sol, $score);
return $score;
}
/***************************************************/
/* Sort callback functions */
/***************************************************/
function sol_compare_callback(&$a, &$b)
{
$r = strlen($b[0]) - strlen($a[0]);
return $r ? $r : strcmp($a[0], $b[0]);
}
function entries_sort_callback($a, $b)
{
if (!$a['maxscore'])
return 1;
return $a['maxscore'] < $b['maxscore'] ? -1 : 1;
}
/***************************************************/
/* Solver class */
/***************************************************/
class solver
{
var $jumbled;
var $history;
var $score;
var $blank;
var $children;
var $best;
function solver($j, $skip = false)
{
global $solveEntryBuffer, $solveEntryLen;
$this->jumbled = $j;
$this->score = 0;
$this->blank = '';
$this->history = array();
if (!$skip)
{
reset($solveEntryBuffer);
while (list($k, ) = each($solveEntryBuffer))
{
$solveEntryLen[$k] = strlen($solveEntryBuffer[$k]);
$this->unexplored[$k] = $k;
}
$this->start(false);
}
}
function __construct($j, $skip = false)
{
$this->solver($j, $skip);
}
function start($current = false, $blank = '')
{
global $solveEntryBuffer, $solveEntryLen, $solveMaxScore, $solveStop, $solveMaxTime;
$this->children = array();
if ($current !== false)
{
$this->score += strlen($solveEntryBuffer[$current]);
unset ($this->unexplored[$current]);
$this->jumbled = removeLetters($solveEntryBuffer[$current], $this->jumbled);
if ($blank != '')
{
$this->blank .= $blank;
$this->history[] = $current.'-'.$blank;
}
else
$this->history[] = $current;
if (!$solveStop && $this->score >= $solveMaxScore || time() > $solveMaxTime)
$solveStop = true;
}
$jblen = strlen($this->jumbled) + 2 - strlen($this->blank);
for (;!is_null($k = key($this->unexplored));next($this->unexplored))
{
if ($solveStop)
break;
if ($solveEntryLen[$k] > $jblen)
continue;
$s = $solveEntryBuffer[$k];
$st = removeLetters($this->jumbled, $s);
if (!strlen($st))
$this->children[$k] = $this->clone($k);
elseif (strlen($st) == 1 && strlen($this->blank) < 2 && (!strlen($this->blank) || $this->blank{0} != $st))
$this->children[$k] = $this->clone($k, $st);
elseif (strlen($st) == 2 && !strlen($this->blank) && $st{0} != $st{1})
$this->children[$k] = $this->clone($k, $st);
}
$max = 0;
for (reset($this->children);!is_null($c = key($this->children));next($this->children))
{
if ($this->children[$c]->score > $max)
{
$max = $this->children[$c]->score;
$this->best = $c;
}
}
if ($max)
$this->score = $max;
}
function clone($current, $blank = '')
{
$new = new solver($this->jumbled, true);
$new->history = $this->history;
$new->score = $this->score;
$new->blank = $this->blank;
$new->unexplored = $this->unexplored;
$new->start($current, $blank);
return $new;
}
}
?>
Back to results
|
|