Scoring
This commit is contained in:
parent
c4e99fccc7
commit
8ea8d66e05
|
@ -1 +1 @@
|
|||
1747
|
||||
1784
|
80
src/DUEL.php
Normal file
80
src/DUEL.php
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
class DUEL{
|
||||
public $rank1;
|
||||
public $rank2;
|
||||
|
||||
private $factor = 400;
|
||||
|
||||
public function __construct($r1,$r2){
|
||||
$this->rank1 = $r1;
|
||||
$this->rank2 = $r2;
|
||||
}
|
||||
private function get_k($rank){
|
||||
if ($rank < 1000) return 80;
|
||||
if ($rank < 2000) return 50;
|
||||
if ($rank <= 2400) return 30;
|
||||
return 20;
|
||||
}
|
||||
private function changeScores($score){
|
||||
$this->rank1 = $this->rank1 + $this->get_k($this->rank1) * ($score - (1/ (1 + pow(10,(($this->rank2 - $this->rank1) / $this->factor)))));
|
||||
$this->rank2 = $this->rank2 + $this->get_k($this->rank2) * (1 - $score - (1/ (1 + pow(10,(($this->rank1 - $this->rank2) / $this->factor)))));
|
||||
}
|
||||
|
||||
public function oneWinsAgainstTwo(){
|
||||
$this->changeScores(1);
|
||||
}
|
||||
public function twoWinsAgainstOne(){
|
||||
$this->changeScores(0);
|
||||
}
|
||||
public function drawGame(){
|
||||
$this->changeScores(0.5);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ELO
|
||||
{
|
||||
public $rank = 1500; //default rank
|
||||
|
||||
public function __construct($v=1500) {
|
||||
$this->rank = $v;
|
||||
}
|
||||
|
||||
private function ELO_get_new_ranks($elo1,$elo2,$score){
|
||||
/*
|
||||
* return an array containing new ELO scores after a battle
|
||||
* $score : 0 player 2 won
|
||||
* 0.5 draws
|
||||
* 1 player 1 won
|
||||
*/
|
||||
|
||||
//good luck for understanding it
|
||||
//(see https://blog.antoine-augusti.fr/2012/06/maths-et-code-le-classement-elo/)
|
||||
return array(
|
||||
$elo1 + ELO_get_k($elo1) * ($score - (1/ (1 + pow(10,(($elo2 - $elo1) / 400))))),
|
||||
$elo2 + ELO_get_k($elo2) * (1 - $score - (1/ (1 + pow(10,(($elo1 - $elo2) / 400)))))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function looseAgainst(ELO $winer){
|
||||
|
||||
}
|
||||
public function winAgainst(ELO $looser){
|
||||
|
||||
}
|
||||
public function drawAgainst(ELO $drawPlayer){
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -20,16 +20,22 @@ class ScoreLap
|
|||
}
|
||||
|
||||
public function getLoosersList(){
|
||||
return $this->$loosers;
|
||||
//return losers as a digest array
|
||||
$arr = array();
|
||||
|
||||
foreach($this->loosers as $looser){
|
||||
$arr[] = array("id" => $looser->id,"order" => $looser->playerIndex);
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
|
||||
private function ApplyDraws(){
|
||||
|
||||
//apply draw match to all losers
|
||||
if(count($this->looserList) < 2) return;
|
||||
if(count($this->loosers) < 2) return;
|
||||
|
||||
foreach($loosers as $$looser1){
|
||||
foreach($loosers as $looser2){
|
||||
foreach($this->loosers as $looser1){
|
||||
foreach($this->loosers as $looser2){
|
||||
if($looser1->playerIndex == $looser2->playerIndex) continue;
|
||||
save_battle('tron', $looser1->id, $looser2->id, 0, 'id' );
|
||||
}
|
||||
|
@ -41,7 +47,7 @@ class ScoreLap
|
|||
|
||||
//need to make losers List. simply array of orders
|
||||
$loosersIndexArr = array();
|
||||
foreach($this->looserList as $looser){
|
||||
foreach($this->loosers as $looser){
|
||||
$loosersIndexArr[] = $looser->playerIndex;
|
||||
}
|
||||
foreach($this->loosers as $looser){
|
||||
|
|
|
@ -18,11 +18,18 @@ class Trail {
|
|||
public function emptyTrail(){
|
||||
$this->trail = new SplStack();
|
||||
}
|
||||
public function mergeWith($trailToMerge){
|
||||
foreach($trailToMerge as $value) {
|
||||
$this->trail->add($value);
|
||||
}
|
||||
public function getTrail(){
|
||||
return $this->trail;
|
||||
}
|
||||
public function mergeWith($trailToMerge){
|
||||
if($trailToMerge->getTrail()->isEmpty()) return;
|
||||
|
||||
foreach($trailToMerge->getTrail() as $value) {
|
||||
$this->trail->push($value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function add($value) {
|
||||
if(!$this->trail->isEmpty()) {
|
||||
if(Trail::kind($this->trail->bottom()) !== Trail::kind($value)) {
|
||||
|
@ -42,7 +49,7 @@ class Trail {
|
|||
public function __toString(){
|
||||
return json_encode($this->getTrailAsArray());
|
||||
}
|
||||
|
||||
|
||||
public function getTrailAsArray(){
|
||||
$arr = array();
|
||||
foreach($this->trail as $coord) {
|
||||
|
|
|
@ -48,14 +48,16 @@ class TronGame
|
|||
foreach($this->bots as $bot){
|
||||
$trailsArr[] = $bot->trail->getTrailAsArray();
|
||||
}
|
||||
//error_log("*********".json_encode($trailsArr,true)."********");
|
||||
return $trailsArr;
|
||||
|
||||
}
|
||||
private function get_map_as_an_unique_trail(){
|
||||
$trail = new Trail;
|
||||
foreach($this->bots as $bot){
|
||||
$trail->mergeWith($bot->trail);
|
||||
}
|
||||
return trail;
|
||||
return $trail;
|
||||
|
||||
}
|
||||
public function get_lasts_trails(){
|
||||
|
@ -125,24 +127,33 @@ class TronGame
|
|||
$response = curl_multi_getcontent($cr);
|
||||
|
||||
if($curlError !== "") {
|
||||
|
||||
//erreur curl, he loses
|
||||
$scoreObj-> addLoser($currentBot);
|
||||
$currentBot->loose();
|
||||
|
||||
error_log("no curl response".$playerIndex); //debug
|
||||
|
||||
}elseif(! $arr = json_decode($response,TRUE)){
|
||||
|
||||
//la reponse n'est pas un json, il a perdu
|
||||
$scoreObj-> addLoser($currentBot);
|
||||
$currentBot->loose();
|
||||
error_log("la reponse est pas JSON".$playerIndex); //debug
|
||||
|
||||
}elseif(Direction::make($arr['play']) === false){
|
||||
|
||||
//tester ici la réponse
|
||||
//he loose il utilise probablement une de ses propres cases
|
||||
$scoreObj-> addLoser($currentBot);
|
||||
$currentBot->loose();
|
||||
error_log("La reponse ne contient pas une direction".$playerIndex); //debug
|
||||
|
||||
}elseif($initialMapAsATrail->contains($currentBot->trail->last()->addDirection(Direction::make($arr['play'])))){ //ounch
|
||||
|
||||
//le bot tente d'aller sur une case qui était prise au début du round
|
||||
$scoreObj-> addLoser($currentBot);
|
||||
$currentBot->loose();
|
||||
error_log("Il joue sur une case deja prise".$playerIndex); //debug
|
||||
}else{
|
||||
//mettre de coté la direction du bot
|
||||
$currentBot->nextDir = Direction::make($arr['play']);
|
||||
|
@ -157,7 +168,7 @@ class TronGame
|
|||
//pour tous les bots encore vivants, on teste si deux d'entre eux ne cibleraient pas la même case
|
||||
foreach ($aliveBots as $bot1){
|
||||
foreach ($aliveBots as $bot2){
|
||||
if($bot1-> $playerIndex == $bot2-> $playerIndex) continue;
|
||||
if($bot1->playerIndex == $bot2->playerIndex) continue;
|
||||
if($bot1->trail->last()->addDirection($bot1->nextDir) == $bot2->trail->last()->addDirection($bot2->nextDir)){
|
||||
//he loose
|
||||
$scoreObj-> addLoser($bot1);
|
||||
|
@ -183,73 +194,7 @@ class TronGame
|
|||
|
||||
|
||||
|
||||
private function get_multi_IAS_Responses($iasUrls, $postParams){
|
||||
//bug here le resultat retourné ne prend pas les bots ayant déjà perdus
|
||||
|
||||
|
||||
//same as the get_IAS_Responses function
|
||||
// but more than one bot requested parallely
|
||||
|
||||
$cmh = curl_multi_init();
|
||||
for ($i = 0; $i < count($iasUrls); $i++){
|
||||
if(isset($postParams[$i])){ //dont use already deads bots
|
||||
$data_string = json_encode($postParams[$i]);
|
||||
|
||||
//error_log($data_string);
|
||||
|
||||
$ch[$i] = curl_init($iasUrls[$i]);
|
||||
curl_setopt($ch[$i], CURLOPT_CUSTOMREQUEST, "POST");
|
||||
curl_setopt($ch[$i], CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch[$i], CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch[$i], CURLOPT_POSTFIELDS, $data_string);
|
||||
curl_setopt($ch[$i], CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch[$i], CURLOPT_HTTPHEADER, array(
|
||||
'Content-Type: application/json',
|
||||
'Content-Length: ' . strlen($data_string))
|
||||
);
|
||||
curl_multi_add_handle($cmh,$ch[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
//send the requests
|
||||
do {
|
||||
$returnVal = curl_multi_exec($cmh, $runningHandles);
|
||||
}while($runningHandles > 0);
|
||||
|
||||
|
||||
//Get results
|
||||
|
||||
for ($i = 0; $i < count($iasUrls); $i++){
|
||||
|
||||
if(isset($postParams[$i])){
|
||||
// Check for errors
|
||||
$curlError = curl_error($ch[$i]);
|
||||
if($curlError == "") {
|
||||
$response = curl_multi_getcontent($ch[$i]);
|
||||
if(! $arr = json_decode($response,TRUE)){
|
||||
$arr=array();
|
||||
}
|
||||
$res[$i] = array(
|
||||
'messageSend' => json_encode($postParams[$i]),
|
||||
'response' => $response,
|
||||
'httpStatus' => curl_getinfo($ch[$i])['http_code'],
|
||||
'responseArr' => $arr
|
||||
);
|
||||
|
||||
}else{
|
||||
$res[$i] = false;
|
||||
}
|
||||
//close
|
||||
curl_multi_remove_handle($cmh, $ch[$i]);
|
||||
curl_close($ch[$i]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
// Clean up the curl_multi handle
|
||||
curl_multi_close($cmh);
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
public function init_game(){
|
||||
//send init messages to bots
|
||||
|
|
|
@ -141,7 +141,7 @@ Les champs qui différent sont:
|
|||
]<br />
|
||||
</p>
|
||||
<p>L'ordre des "queues" des serpents dans ce tableau correspond à l'ordre des joueurs. Donc votre serpent est representée par la queue correspondant à player-index (le décompte de player-index commence par 0).</p>
|
||||
<p>L'ordre des couples de coordonnées de chaque bot, est dans le sens queue vers la tête. Les bots grandissent à chaque tour en déplaçant leur tête.</p>
|
||||
<p>L'ordre des couples de coordonnées de chaque bot, est dans le sens tête vers queue. Les bots grandissent à chaque tour en déplaçant leur tête.</p>
|
||||
<h2>Scoring</h2>
|
||||
<p>Le scorring (classement EHLO) reste sur une logique de duels, bien que ce jeu puisse contenir plus de deux bots par match. Le score est modifié au fur et à mesure de la partie à chaque fois qu'un bot "décède":</p>
|
||||
<ul>
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
# http://www.gnu.org/licenses/gpl-3.0-standalone.html
|
||||
#
|
||||
# -- END LICENSE BLOCK -----------------------------------------
|
||||
include(__DIR__."/DUEL.php");
|
||||
|
||||
function get_arenas_list(){
|
||||
include (__DIR__."/arenas_lists.php");
|
||||
|
@ -203,99 +204,73 @@ function ELO_get_podium($arena){
|
|||
}
|
||||
return $podium;
|
||||
}
|
||||
function ELO_get_k($elo){
|
||||
if ($elo < 1000){
|
||||
return 80;
|
||||
}
|
||||
if ($elo < 2000){
|
||||
return 50;
|
||||
}
|
||||
if ($elo <= 2400){
|
||||
return 30;
|
||||
}
|
||||
return 20;
|
||||
}
|
||||
function ELO_get_new_ranks($elo1,$elo2,$score){
|
||||
|
||||
|
||||
function save_battle($game,$bot1,$bot2,$result,$nameOrIds = 'name'){
|
||||
/*
|
||||
* return an array containing new ELO scores after a battle
|
||||
* $score : 0 player 2 won
|
||||
* 0.5 draws
|
||||
* 1 player 1 won
|
||||
*/
|
||||
|
||||
//good luck for understanding it
|
||||
//(see https://blog.antoine-augusti.fr/2012/06/maths-et-code-le-classement-elo/)
|
||||
return array(
|
||||
$elo1 + ELO_get_k($elo1) * ($score - (1/ (1 + pow(10,(($elo2 - $elo1) / 400))))),
|
||||
$elo2 + ELO_get_k($elo2) * (1 - $score - (1/ (1 + pow(10,(($elo1 - $elo2) / 400)))))
|
||||
);
|
||||
}
|
||||
|
||||
function save_battle($game,$bot1,$bot2,$resultat,$nameOrIds = 'name'){
|
||||
//$bots1 and $bots2 are bots'names
|
||||
//resultat: 0 match nul, 1 bot1 gagne 2 bot 2 gagne
|
||||
|
||||
* Calculate new ELO ranks and save them on conn_bdd
|
||||
*/
|
||||
|
||||
global $lnMysql;
|
||||
$game=substr($game,0,8); //limit 8 char for limitting mysql index size
|
||||
|
||||
if($nameOrIds == "name"){
|
||||
//chercher les id de bot 1 et bot2
|
||||
$rs=mysqli_query($lnMysql,"SELECT name,id,ELO FROM bots
|
||||
WHERE name='".mysqli_real_escape_string($lnMysql,$bot1)."'
|
||||
OR name='".mysqli_real_escape_string($lnMysql,$bot2)."'");
|
||||
|
||||
if($nameOrIds == "name"){
|
||||
for( $i=1; $i<3; $i++){
|
||||
$str = "bot".$i;
|
||||
$botName = $$str;
|
||||
$rs=mysqli_query($lnMysql,"SELECT id,ELO FROM bots WHERE name='".mysqli_real_escape_string($lnMysql,$botName)."'");
|
||||
$r = mysqli_fetch_row($rs);
|
||||
$bot[$i] = array(
|
||||
'id' => $r[0],
|
||||
'ELO' => $r[1]
|
||||
);
|
||||
}
|
||||
}else{
|
||||
$rs = mysqli_query($lnMysql, "SELECT name,id,ELO FROM bots
|
||||
WHERE id='".mysqli_real_escape_string($lnMysql,$bot1)."'
|
||||
OR id='".mysqli_real_escape_string($lnMysql,$bot2)."'");
|
||||
}
|
||||
while($r=mysqli_fetch_row($rs)){
|
||||
$bots[$r[0]]=$r[1];
|
||||
$actualELO[$r[0]]=$r[2];
|
||||
//the same, but query by id
|
||||
for( $i=1; $i<3; $i++){
|
||||
$str = "bot".$i;
|
||||
$botName = $$str;
|
||||
$rs=mysqli_query($lnMysql,"SELECT id,ELO FROM bots WHERE id='".mysqli_real_escape_string($lnMysql,$botName)."'");
|
||||
$r = mysqli_fetch_row($rs);
|
||||
$bot[$i] = array(
|
||||
'id' => $r[0],
|
||||
'ELO' => $r[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if((!isset($bots[$bot1])) OR (!isset($bots[$bot2]))){
|
||||
error (500,"database corrupt");
|
||||
die;
|
||||
}
|
||||
|
||||
switch($resultat){
|
||||
//apply $result
|
||||
$duel = new DUEL( $bot[1]["ELO"] , $bot[2]["ELO"]);
|
||||
|
||||
switch ($result){
|
||||
case 0:
|
||||
$duel->drawGame();
|
||||
$field="nulCount";
|
||||
$eloScore = 0.5;
|
||||
break;
|
||||
case 1:
|
||||
$field="player1_winsCount";
|
||||
$eloScore = 1;
|
||||
$duel->oneWinsAgainstTwo();
|
||||
$field="player1_winsCount";
|
||||
break;
|
||||
case 2:
|
||||
$field="player2_winsCount";
|
||||
$eloScore = 0;
|
||||
break;
|
||||
$duel->twoWinsAgainstOne();
|
||||
$field="player2_winsCount";
|
||||
break;
|
||||
default:
|
||||
error (500,"something impossible has happened");
|
||||
error (500,"Oups");
|
||||
break;
|
||||
}
|
||||
|
||||
$newRanks = ELO_get_new_ranks($actualELO[$bot1],$actualELO[$bot2],$eloScore);
|
||||
|
||||
mysqli_multi_query($lnMysql,
|
||||
"
|
||||
UPDATE bots
|
||||
SET ELO='".$newRanks[0]."'
|
||||
WHERE id='".$bots[$bot1]."';
|
||||
|
||||
UPDATE bots
|
||||
SET ELO='".$newRanks[1]."'
|
||||
WHERE id='".$bots[$bot2]."';
|
||||
|
||||
|
||||
INSERT INTO arena_history(game,player1_id,player2_id,".$field.") VALUES
|
||||
//update ELO rank on database
|
||||
mysqli_multi_query($lnMysql,"
|
||||
UPDATE bots SET ELO = '".$duel->rank1."' WHERE id='".$bot[1]["id"]."';
|
||||
UPDATE bots SET ELO = '".$duel->rank2."' WHERE id='".$bot[2]["id"]."';
|
||||
INSERT INTO arena_history(game,player1_id,player2_id,".$field.") VALUES
|
||||
('".mysqli_real_escape_string($lnMysql,$game)."',
|
||||
'".$bots[$bot1]."',
|
||||
'".$bots[$bot2]."',
|
||||
'".$bot[1]["id"]."',
|
||||
'".$bot[2]["id"]."',
|
||||
'1')
|
||||
ON DUPLICATE KEY UPDATE ".$field." = ".$field." + 1;");
|
||||
|
||||
ON DUPLICATE KEY UPDATE ".$field." = ".$field." + 1;
|
||||
");
|
||||
}
|
||||
function get_unique_id(){
|
||||
//increment the number
|
||||
|
|
Loading…
Reference in New Issue
Block a user