#!/usr/bin/perl # Make a pool of random players with known true ratings between 1000 to 2000 # Set the calculated ratings to be the same as the true ratings # Play games between randomly selected players with the outcome # determined by the true ratings # Calculate the system error $MaxPlayers = 10; print "# players = $MaxPlayers\n"; print "drift test: 100 trials, skip Px100 games, measure error for Px10 games\n"; $e = drift(100, $MaxPlayers*100, $MaxPlayers*10); print " drift error: $e rating points\n"; print "convergence test: 100 trials, stop when error gets below $e\n"; $c = convergence(100, $e); print " convergence rate: $c games per player\n"; print "disruption test: 100 trials, stop when error gets below $e\n"; ($r, $c) = disruption(100, $e); print " disruption error: $r rating points\n"; print " disruption rate: $c games per player\n"; exit; sub disruption{ local($trials, $conv) = @_; local($i, $j, $merr, $err, $c, $tc, $terr); $tc= 0; for($i=0;$i<$trials;$i++){ tryAgain: makePlayers(); for($j=0;$j<$MaxPlayers;$j++){ $Cr[$j] = 1500; } $MaxPlayers -= 1; $err = playGames($MaxPlayers-1); while($err>$conv){ $err = playGames($MaxPlayers-1); #print " $err\n"; } $MaxPlayers += 1; #print "converged $Cr[$MaxPlayers-1] $Tr[$MaxPlayers-1]\n"; $merr = playGames($MaxPlayers); if (abs($merr-$err)<5){ goto tryAgain; } $err = $merr; #print " $err\n"; $c = 1; while($merr>$conv){ $merr = playGames($MaxPlayers); #print " $merr\n"; $err += $merr; $c += 1; } #print " $c\n"; $tc += $c; $terr += $err; } # Normalize the result so that it gives the number of games each # player has to play print " terr is $terr tc is $tc\n"; $terr = $terr/$tc; $tc = $tc/$trials; $tc = $tc*2; # because if there are 10 players and 10 total games played # then on average each player got to play 2 games #print "$tc\n"; return ($terr, $tc); } sub convergence{ local($trials, $conv) = @_; local($i, $j, $err, $c, $tc); $tc= 0; for($i=0;$i<$trials;$i++){ makePlayers(); for($j=0;$j<$MaxPlayers;$j++){ $Cr[$j] = 1500; } $err = playGames($MaxPlayers); $c = $MaxPlayers; while($err>$conv){ $err = playGames($MaxPlayers); #print " $i $err\n"; $c += $MaxPlayers; } #print " $c\n"; $tc += $c; } # Normalize the result so that it gives the number of games each # player has to play $tc = $tc/$MaxPlayers/$trials; $tc = $tc*2; # because if there are 10 players and 10 total games played # then on average each player got to play 2 games #print "$tc\n"; return $tc; } sub drift{ local($trials, $skip, $games) = @_; local($i, $err, $terr); $terr = 0; for($i=0;$i<$trials;$i++){ makePlayers(); @Cr = @Tr; $err = playGames($skip); $err = playGames($games); $terr += $err; #print " $err\n"; } return $terr/$trials; } sub makePlayers{ local($i); for($i=0;$i<$MaxPlayers;$i++){ $Tr[$i] = int(rand(1000)) + 1000; } } sub playGames{ local($ng) = @_; local($i, $p1, $p2, $outcome, $err, $terr); local($err2, $err3); $err = 0; for($i=0;$i<$ng;$i++){ selectPlayers: $p1 = int(rand($MaxPlayers)); $p2 = int(rand($MaxPlayers)); #print "p1=$p1 p2=$p2\n"; if ($p1==$p2){ goto selectPlayers; } $outcome = playGame($p1, $p2); updateRatings($p1, $p2, $outcome); $err = sysErr(\@Tr, \@Cr); $terr += $err; #print " $err\n"; } return $terr/$ng; } sub playGame{ local($p1, $p2) = @_; return outcome($Tr[$p1], $Tr[$p2]); } sub outcome{ local($r1, $r2) = @_; local($rdiff, $wp, $ran); $rdiff = ($r2 - $r1)/400; $wp = 1.0/(1.0 + 10.0**$rdiff); $ran = rand(1); if ($ran<$wp){ return 1;} return 0; } sub updateRatings{ local($p1, $p2, $w1) = @_; ($r1) = newRating($Cr[$p1], $Cr[$p2], $w1); ($r2) = newRating($Cr[$p2], $Cr[$p1], 1 - $w1); $Cr[$p1] = $r1; $Cr[$p2] = $r2; } sub newRating{ local($mr, $or, $iwon) = @_; local($rdiff, $wp, $k, $nr); $rdiff = ($or - $mr)/400; $wp = 1.0/(1.0 + 10.0**$rdiff); $k = 24; $nr = int($mr + $k*($iwon - $wp) + 0.5); return $nr; } sub sysErr{ local($t, $c) = @_; local(@tr) = @$t; local(@cr) = @$c; local($i, $j, $err); $err = 0; for($i=0;$i<$MaxPlayers;$i++){ for($j=0;$j<$i;$j++){ if ($i!=$j){ #print " $i $j $err += abs(abs($tr[$i]-$tr[$j]) - abs($cr[$i]-$cr[$j])) \n"; $err += abs(abs($tr[$i]-$tr[$j]) - abs($cr[$i]-$cr[$j])); } } } #print " return $err/($MaxPlayers-1)/$MaxPlayers \n"; return $err/($MaxPlayers-1)/$MaxPlayers; } # Dont use these error function; they dont give good results sub sysErr2{ local($t, $c) = @_; local(@tr) = @$t; local(@cr) = @$c; local($i, $j, $err); $err = 0; for($i=0;$i<$MaxPlayers;$i++){ $err += abs($tr[$i]-$cr[$i]); } return $err/$MaxPlayers; } # Dont use these error function; they dont give good results sub sysErr3{ local($t, $c) = @_; local(@tr) = @$t; local(@cr) = @$c; local($i, $j, $err, $avtr, $avcr); $err = 0; for($i=0;$i<$MaxPlayers;$i++){ $err += abs($tr[$i]-$cr[$i]); $avtr += $tr[$i]; $avcr += $cr[$i]; } $j = $avtr - $avcr; print " $j $avtr $avcr\n"; $err = abs($err - ($avtr - $avcr)); return $err/$MaxPlayers; }