 <p>This is an open-ended question and there is no clear answer with different tradeoffs.. I'm not a PHP programmer, but something like the following should work.</p> <pre><code># THESE PARAMETERS CONTROL THE RANKING ALGORITHM. $rescale = 0; $spread = 1; function rescore ($n) { return log($n) + $rescale; } function rank ($scores) { return 100 / (1 + exp(- $spread * array_sum(array_map("rescore", $scores)))); } </code></pre> <p>You should choose <code>$rescale</code> so that the average score rescores to something close to 0. And play around with <code>$spread</code> until you're happy with how much your scores spread out.</p> <p>The idea is that <code>log</code> turns a wide range of scores into numbers in a comparable range that can be positive or negative. Add a bunch of rescored scores together and you get an arbitrary real number. Then throw that into a logistic function (see <a href="https://en.wikipedia.org/wiki/Logistic_function" rel="nofollow">https://en.wikipedia.org/wiki/Logistic_function</a> for details) to turn that into a number in your desired range.</p>