Merge branch 'tron' of github.com:gnieark/botsArena into tron
This commit is contained in:
commit
49ed343300
|
@ -1 +1 @@
|
|||
1448
|
||||
1617
|
|
@ -1 +1 @@
|
|||
Subproject commit 7c8b786228bb9e1561ff60a2d6f7f6ce91be6fee
|
||||
Subproject commit 1d85f9ef3ecfc42bbc4f3c70d5e37ca9a65f629a
|
22
src/arenas/tron/Coords.php
Normal file
22
src/arenas/tron/Coords.php
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
class Coords{
|
||||
|
||||
public $x;
|
||||
public $y;
|
||||
|
||||
public function __construct(int $x = 0, int $y = 0) {
|
||||
$this->x = $x;
|
||||
$this->y = $y;
|
||||
}
|
||||
|
||||
public function __toString(){
|
||||
return $this->x.",".$this->y;
|
||||
}
|
||||
|
||||
public function addDirection(Direction $dir){
|
||||
return new Coords(
|
||||
$this->x + $dir->deltaX,
|
||||
$this->y + $dir->deltaY
|
||||
);
|
||||
}
|
||||
}
|
92
src/arenas/tron/Direction.php
Normal file
92
src/arenas/tron/Direction.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
class InvalidDirectionException extends UnexpectedValueException{
|
||||
|
||||
}
|
||||
class Direction
|
||||
{
|
||||
private static $top = 0;
|
||||
private static $bottom = 1;
|
||||
private static $left = 2;
|
||||
private static $right = 3;
|
||||
|
||||
private $value;
|
||||
|
||||
public $deltaX;
|
||||
public $deltaY;
|
||||
|
||||
public function __construct(){
|
||||
$this->value = 0;
|
||||
}
|
||||
|
||||
private function setValue($value){
|
||||
$this->value = $value;
|
||||
switch ($value){
|
||||
case Direction::$bottom:
|
||||
$this->deltaY = -1;
|
||||
$this->deltaX = 0;
|
||||
break;
|
||||
case Direction::$top:
|
||||
$this->deltaY = 1;
|
||||
$this->deltaX = 0;
|
||||
break;
|
||||
case Direction::$left:
|
||||
$this->deltaY = 0;
|
||||
$this->deltaX = -1;
|
||||
break;
|
||||
case Direction::$right:
|
||||
$this->deltaY = 0;
|
||||
$this->deltaX = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString(){
|
||||
switch ($this->value){
|
||||
case Direction::$top:
|
||||
return "y+";
|
||||
break;
|
||||
case Direction::$bottom:
|
||||
return "y-";
|
||||
break;
|
||||
case Direction::$left:
|
||||
return "x-";
|
||||
break;
|
||||
case Direction::$right:
|
||||
return "x+";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static function make($str){
|
||||
$dir = new Direction();
|
||||
switch((string)$str){
|
||||
case "x+":
|
||||
$dir->setValue(Direction::$right);
|
||||
break;
|
||||
case "x-":
|
||||
$dir->setValue(Direction::$left);
|
||||
break;
|
||||
case "y+":
|
||||
$dir->setValue(Direction::$top);
|
||||
break;
|
||||
case "y-":
|
||||
$dir->setValue(Direction::$bottom);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidDirectionException("expected 'x+', 'x-', 'y+' or 'y-'". (string)$str."received.");
|
||||
}
|
||||
return $dir;
|
||||
}
|
||||
public function opposite(){
|
||||
$opposites = array(
|
||||
Direction::$top => Direction::$bottom,
|
||||
Direction::$bottom => Direction::$top,
|
||||
Direction::$left => Direction::$right,
|
||||
Direction::$right => Direction::$left
|
||||
);
|
||||
|
||||
$opposite = new Direction();
|
||||
$opposite->setValue($opposites[$this->value]);
|
||||
return $opposite;
|
||||
}
|
||||
}
|
59
src/arenas/tron/Trail.php
Normal file
59
src/arenas/tron/Trail.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
class AlreadyBeenAddedException extends LogicException { }
|
||||
|
||||
class Trail {
|
||||
private $trail;
|
||||
|
||||
public function __construct() {
|
||||
$this->trail = new SplStack();
|
||||
}
|
||||
|
||||
public function last() {
|
||||
return $this->trail->top();
|
||||
}
|
||||
|
||||
public function emptyTrail(){
|
||||
$this->trail = new SplStack();
|
||||
}
|
||||
|
||||
public function add($value) {
|
||||
if(!$this->trail->isEmpty()) {
|
||||
if(Trail::kind($this->trail->bottom()) !== Trail::kind($value)) {
|
||||
throw new TypeError(
|
||||
'items added to a trail must be of the same kind'
|
||||
);
|
||||
}
|
||||
|
||||
if($this->contains($value)) {
|
||||
throw new AlreadyBeenAddedException(
|
||||
'value has already been added to the trail'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->trail->push($value);
|
||||
}
|
||||
public function __toString(){
|
||||
return json_encode($this->getTrailAsArray());
|
||||
}
|
||||
public function getTrailAsArray(){
|
||||
$arr = array();
|
||||
foreach($this->trail as $coord) {
|
||||
$arr[] = array($coord->x,$coord->y);
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
public function contains($searchedValue) {
|
||||
foreach($this->trail as $value) {
|
||||
if($value == $searchedValue) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function kind($var) {
|
||||
$type = gettype($var);
|
||||
if($type == 'object') $type .= ' ' . get_class($var);
|
||||
return $type;
|
||||
}
|
||||
}
|
260
src/arenas/tron/TronGame.php
Normal file
260
src/arenas/tron/TronGame.php
Normal file
|
@ -0,0 +1,260 @@
|
|||
<?php
|
||||
class TronGame
|
||||
{
|
||||
private $bots; //array of bots
|
||||
public $gameId;
|
||||
private $status; //false => Game ended or not initialised
|
||||
|
||||
public function get_continue(){
|
||||
//count bots alive. if less than 1, game is ended
|
||||
$count = 0;
|
||||
foreach($this->bots as $bot){
|
||||
if( $bot->isAlive == true){
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
if($count > 1){
|
||||
return true;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function apply_looses($loosersArr){
|
||||
//save draws
|
||||
if( count($loosersArr) > 1 ){
|
||||
$loosersById = array();
|
||||
foreach($loosersArr as $bot){
|
||||
$loosersById[] = $this->bots[$bot]->id;
|
||||
}
|
||||
$this->save_draw_bots($loosersById);
|
||||
}
|
||||
|
||||
//save victories
|
||||
if( count($loosersArr) > 0 ){
|
||||
//make victorous bots array
|
||||
$vbots = array();
|
||||
for ($botCount = 0; $botCount < $nbeBots; $botCount++){
|
||||
if($this->bots[$botCount]->isAlive){
|
||||
$vbots[] = $this->bots[$botCount]->id;
|
||||
}
|
||||
}
|
||||
$this->save_losers_winers($loosersById,$vbots);
|
||||
}
|
||||
|
||||
}
|
||||
private function save_draw_bots($arr){
|
||||
/*
|
||||
* Recursive function who save all combionaisons of draw matches
|
||||
*/
|
||||
|
||||
if(count($arr) < 2){
|
||||
return;
|
||||
}else{
|
||||
$a = $arr[0];
|
||||
array_shift($arr);
|
||||
foreach($arr as $bot){
|
||||
save_battle('tron',$a,$bot,0,'id');
|
||||
}
|
||||
$this->save_draw_bots($arr);
|
||||
}
|
||||
}
|
||||
|
||||
private function save_losers_winers($arrLoosers,$arrWiners){
|
||||
foreach($arrWiners as $winner){
|
||||
foreach($arrLoosers as $loser){
|
||||
save_battle('tron',$winer,$loser,1,'id');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function get_trails(){
|
||||
//return all trails for draw svg
|
||||
$trailsArr = array();
|
||||
foreach($this->bots as $bot){
|
||||
$trailsArr[] = $bot->trail->getTrailAsArray();
|
||||
}
|
||||
return $trailsArr;
|
||||
}
|
||||
public function new_lap(){
|
||||
// for all alive bots
|
||||
$logs = "";
|
||||
$nbeBots = count($this->bots);
|
||||
$urls = array();
|
||||
$paramToSend = array();
|
||||
$board = $this->get_trails();
|
||||
$loosers = array();
|
||||
$lastsCells = array();
|
||||
|
||||
for ($botCount = 0; $botCount < $nbeBots; $botCount++){
|
||||
if ($this->bots[$botCount]->isAlive){
|
||||
|
||||
$urls[$botCount] = $this->bots[$botCount]->url;
|
||||
|
||||
$paramsToSend[$botCount] = array(
|
||||
'game-id' => "".$this->gameId,
|
||||
'action' => 'play-turn',
|
||||
'game' => 'tron',
|
||||
'board' => $board,
|
||||
'player-index' => $botCount, // To do: verifier que ça restera le même à chaque tour
|
||||
'players' => $nbeBots
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$responses = $this->get_multi_IAS_Responses($urls,$paramsToSend);
|
||||
//print_r($responses);
|
||||
//grow bots'tails
|
||||
for ($botCount = 0; $botCount < $nbeBots; $botCount++){
|
||||
if ($this->bots[$botCount]->isAlive){
|
||||
|
||||
$dir = Direction::make($responses[$botCount]['responseArr']['play']);
|
||||
|
||||
$lastsCells[$botCount] = $this->bots[$botCount]->grow($dir);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//test if loose
|
||||
for ($botCount = 0; $botCount < $nbeBots; $botCount++){
|
||||
if ($this->bots[$botCount]->isAlive){
|
||||
for( $botCount2 = 0; $botCount2 < $nbeBots; $botCount2++){
|
||||
|
||||
if(($botCount <> $botCount2)
|
||||
&& ($this->bots[$botCount2]->trail->contains($lastsCells[$botCount]))
|
||||
){
|
||||
$loosers[] = $botCount;
|
||||
$this->bots[$botCount]->loose();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->get_trails();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private function get_multi_IAS_Responses($iasUrls, $postParams){
|
||||
//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++){
|
||||
$data_string = json_encode($postParams[$i]);
|
||||
|
||||
$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 ($returnVal == CURLM_CALL_MULTI_PERFORM);
|
||||
// Loop and continue processing the request
|
||||
while ($runningHandles && $returnVal== CURLM_OK) {
|
||||
// Wait forever for network
|
||||
$numberReady = curl_multi_select($cmh);
|
||||
if ($numberReady != -1) {
|
||||
// Pull in any new data, or at least handle timeouts
|
||||
do {
|
||||
$returnVal = curl_multi_exec($cmh, $runningHandles);
|
||||
} while ($returnVal == CURLM_CALL_MULTI_PERFORM);
|
||||
}
|
||||
}
|
||||
|
||||
//Get results
|
||||
for ($i = 0; $i < count($iasUrls); $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
|
||||
$logs = "";
|
||||
$fullLogs = "";
|
||||
$nbeBots = count($this->bots);
|
||||
for ($botCount = 0; $botCount < $nbeBots; $botCount++){
|
||||
$messageArr = array(
|
||||
'game-id' => "".$this->gameId,
|
||||
'action' => 'init',
|
||||
'game' => 'tron',
|
||||
'board' => '',
|
||||
'players' => $nbeBots,
|
||||
'player-index' => $botCount
|
||||
);
|
||||
|
||||
$resp = get_IA_Response($this->bots[$botCount]->url,$messageArr);
|
||||
$fullLogs .= 'Arena send to '.$this->bots[$botCount]->name.'<em>'.htmlentities($resp['messageSend']).'</em><br/>
|
||||
HTTP status: <em>'.htmlentities($resp['httpStatus']).'</em><br/>
|
||||
Bot anwser: <em>'.htmlentities($resp['response']).'</em><br/>';
|
||||
$logs.="Init message send to ".$this->bots[$botCount]->name."<br/>";
|
||||
}
|
||||
return array($logs,$fullLogs);
|
||||
}
|
||||
|
||||
public function __construct($botsInfos){
|
||||
$this->gameId = get_unique_id();
|
||||
$this->bots = array();
|
||||
$positions = array();
|
||||
$botCount = 0;
|
||||
$err = "";
|
||||
|
||||
//print_r($botsInfos);
|
||||
|
||||
foreach($botsInfos as $bot){
|
||||
//find a random start position
|
||||
do{
|
||||
$x = rand(1,999);
|
||||
$y = rand(1,999);
|
||||
}while(in_array($x.",".$y,$positions));
|
||||
|
||||
$positions[] = $x.",".$y;
|
||||
$startCoord = new Coords($x,$y);
|
||||
|
||||
$this->bots[$botCount] = new TronPlayer();
|
||||
$this->bots[$botCount]->make($bot['id'],$startCoord,$bot['name'],$bot['url']);
|
||||
|
||||
if ($this->bots[$botCount]->isAlive === false){
|
||||
$err .= "Something went wrong for ".$this->bots[$botCount]->getName()."<br/>";
|
||||
}else{
|
||||
$botCount++;
|
||||
}
|
||||
}
|
||||
return $err;
|
||||
}
|
||||
}
|
30
src/arenas/tron/TronPlayer.php
Normal file
30
src/arenas/tron/TronPlayer.php
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
class TronPlayer{
|
||||
public $url;
|
||||
public $id;
|
||||
public $name;
|
||||
public $trail;
|
||||
private $direction;
|
||||
public $isAlive = true;
|
||||
|
||||
public function grow(Direction $dir){
|
||||
$this->trail->add($this->trail->last()->addDirection($dir));
|
||||
return $this->trail->last();
|
||||
}
|
||||
public function loose(){
|
||||
$this->isAlive = false;
|
||||
$this->trail->emptyTrail();
|
||||
return false;
|
||||
}
|
||||
public function make($botId, Coords $initialsCoords,$name,$url){
|
||||
$this->id = $botId;
|
||||
$this->trail = new Trail;
|
||||
$this->trail->add($initialsCoords);
|
||||
$this->name = $name;
|
||||
$this->url = $url;
|
||||
$this->state = true;
|
||||
}
|
||||
public function __construct(){
|
||||
$this->state = false;
|
||||
}
|
||||
}
|
87
src/arenas/tron/act.php
Normal file
87
src/arenas/tron/act.php
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
#- BEGIN LICENSE BLOCK ---------------------------------------
|
||||
#
|
||||
# This file is part of botsArena.
|
||||
#
|
||||
# Copyright (C) Gnieark et contributeurs
|
||||
# Licensed under the GPL version 3.0 license.
|
||||
# See LICENSE file or
|
||||
# http://www.gnu.org/licenses/gpl-3.0-standalone.html
|
||||
#
|
||||
# -- END LICENSE BLOCK -----------------------------------------
|
||||
|
||||
require_once ("TronGame.php");
|
||||
require_once ("TronPlayer.php");
|
||||
require_once ("Direction.php");
|
||||
require_once ("Trail.php");
|
||||
require_once ("Coords.php");
|
||||
|
||||
switch ($_POST['act']){
|
||||
case "initGame":
|
||||
|
||||
$rs = mysqli_query($lnMysql,"SELECT id,name,url FROM bots WHERE game='tron';");
|
||||
while($r = mysqli_fetch_row($rs)){
|
||||
$botsFullArr[$r[0]] = array('id' => $r[0], 'name' => $r[1], 'url' => $r[2]);
|
||||
}
|
||||
|
||||
|
||||
$botsArrayTemp = json_decode($_POST['bots']);
|
||||
$botsInfos = array();
|
||||
|
||||
foreach($botsArrayTemp as $id){
|
||||
//tester si le bot existe dans la bdd
|
||||
if(isset($botsFullArr[$id])){
|
||||
$botsInfos[] = $botsFullArr[$id];
|
||||
}
|
||||
}
|
||||
//************
|
||||
$game = new TronGame($botsInfos);
|
||||
|
||||
|
||||
$logs = $game->init_game();
|
||||
|
||||
echo json_encode(array(
|
||||
'status' => $game->get_continue(),
|
||||
'logs' => $logs,
|
||||
'gameId' => $game->gameId,
|
||||
'botsPosition' => $game->get_trails()
|
||||
));
|
||||
|
||||
$_SESSION['game'] = serialize($game);
|
||||
|
||||
|
||||
die;
|
||||
break;
|
||||
case "play":
|
||||
$logs = "";
|
||||
if(!isset($_SESSION['game'])){
|
||||
echo '{"status":"error"}';
|
||||
die;
|
||||
}
|
||||
|
||||
$game = unserialize($_SESSION['game']);
|
||||
|
||||
if($game->gameId <> $_POST['gameId']){
|
||||
//sometimes if an ajax callback is applied after init an other game
|
||||
echo '{"status":"error"}';
|
||||
die;
|
||||
}
|
||||
$lap = $game->new_lap();
|
||||
if($game->get_continue()){
|
||||
$continue = 1;
|
||||
}else{
|
||||
$continue = 0;
|
||||
}
|
||||
echo json_encode(array(
|
||||
'gameId' => $game->gameId,
|
||||
'continue' => $continue,
|
||||
'lap' => $lap
|
||||
));
|
||||
$_SESSION['game'] = serialize($game);
|
||||
die;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
0
src/arenas/tron/doc-en.html
Normal file
0
src/arenas/tron/doc-en.html
Normal file
0
src/arenas/tron/doc-fr.html
Normal file
0
src/arenas/tron/doc-fr.html
Normal file
5
src/arenas/tron/functions.php
Normal file
5
src/arenas/tron/functions.php
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?php
|
||||
|
||||
|
||||
|
||||
|
167
src/arenas/tron/js.js
Normal file
167
src/arenas/tron/js.js
Normal file
|
@ -0,0 +1,167 @@
|
|||
function createElem(type,attributes){
|
||||
var elem=document.createElement(type);
|
||||
for (var i in attributes)
|
||||
{elem.setAttribute(i,attributes[i]);}
|
||||
return elem;
|
||||
}
|
||||
function addLog(message){
|
||||
var divLogs = document.getElementById("logs");
|
||||
var p=createElem('p',{});
|
||||
p.innerHTML=message;
|
||||
divLogs.appendChild(p);
|
||||
divLogs.scrollTop = divLogs.scrollHeight;
|
||||
|
||||
}
|
||||
function growTails(newPointsByPlayer){
|
||||
|
||||
var botsColor = ['cyan','darkmagenta','darkred','darkslategrey','deeppink','dodgerblue','goldenrod','grey','indigo','lightgreen','mediumslateblue','midnightblue'];
|
||||
//document.getElementById('map');
|
||||
for (var botId in newPointsByPlayer){
|
||||
|
||||
var tail = newPointsByPlayer[botId]['tail'];
|
||||
for(var coordsIx in tail){
|
||||
|
||||
coords = tail[coordsIx];
|
||||
//draw the point
|
||||
var rect=createElemNS('rect',{'x':coords[0],'y':coords[1],'width':'2','height':'2','style':'fill:' + botsColor[botId] + ';'});
|
||||
document.getElementById('map').appendChild(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
function createElemNS(type,attributes){
|
||||
//same as createElem but with ns for svg file
|
||||
var elem=document.createElementNS("http://www.w3.org/2000/svg",type);
|
||||
for (var i in attributes)
|
||||
{elem.setAttributeNS(null,i,attributes[i]);}
|
||||
return elem;
|
||||
}
|
||||
function changeSelect(number,botId){
|
||||
//show an other selector if bot is chosen
|
||||
var next = parseInt(number) + 1;
|
||||
if((botId > 0) && (number < 12)){
|
||||
if(document.getElementById('selectBot' + next)){
|
||||
return;
|
||||
}else{
|
||||
show_bot_panel(next);
|
||||
}
|
||||
if(number > 0){
|
||||
document.getElementById('fightButton').disabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
function show_bot_panel(number){
|
||||
//configurePlayers
|
||||
var fieldset = createElem('fieldset',{'class':'botFormulaire'});
|
||||
var legend = createElem('legend',{});
|
||||
legend.innerHTML = 'bot ' + number;
|
||||
fieldset.appendChild(legend);
|
||||
var p=createElem('p');
|
||||
var select = createElem('select',{'id':'selectBot' + number, 'onchange':'changeSelect(' + number + ',this.value);'});
|
||||
var option = createElem('option',{'value': '0', 'selected': 'selected','disabled':'disabled'});
|
||||
option.innerHTML = '';
|
||||
select.appendChild(option);
|
||||
for (var i = 0; i < botsAvailable.length; i++){
|
||||
var option = createElem('option',{'value': botsAvailable[i]['id']});
|
||||
option.innerHTML = botsAvailable[i]['name'];
|
||||
select.appendChild(option);
|
||||
}
|
||||
p.appendChild(select);
|
||||
fieldset.appendChild(p);
|
||||
|
||||
document.getElementById('configurePlayers').appendChild(fieldset);
|
||||
}
|
||||
|
||||
function applyInitMessage(req,xd_check){
|
||||
document.getElementById('fightButton').disabled=true;
|
||||
//callback function when init game request
|
||||
if(req.readyState == 4){
|
||||
if(req.status == 200) {
|
||||
//alert (req.responseText);
|
||||
try{
|
||||
var ret = JSON.parse(req.responseText);
|
||||
}catch(e){
|
||||
addLog('erreur' + req.responseText);
|
||||
return;
|
||||
}
|
||||
addLog(ret['logs']);
|
||||
if(ret['status'] == true){
|
||||
growTails(ret['botsPosition']);
|
||||
play(ret['gameId'],xd_check);
|
||||
}
|
||||
|
||||
}else{
|
||||
alert ('error ' + req.status);
|
||||
document.getElementById('fightButton').disabled=false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function drawMap(map){
|
||||
console.log(map);
|
||||
var botsColor = ['cyan','darkmagenta','darkred','darkslategrey','deeppink','dodgerblue','goldenrod','grey','indigo','lightgreen','mediumslateblue','midnightblue'];
|
||||
|
||||
for (var botId in map){
|
||||
for(var coordsI in map[botId]){
|
||||
coords = map[botId][coordsI];
|
||||
//draw the point
|
||||
var rect=createElemNS('rect',{'x':coords[0],'y':coords[1],'width':'2','height':'2','style':'fill:' + botsColor[botId] + ';'});
|
||||
document.getElementById('map').appendChild(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function play(gameId,xd_check){
|
||||
|
||||
var req = new XMLHttpRequest();
|
||||
req.onreadystatechange = function(){
|
||||
if(req.readyState == 4){
|
||||
if(req.status == 200) {
|
||||
addLog(req.responseText);
|
||||
var reponse = JSON.parse(req.responseText);
|
||||
|
||||
|
||||
|
||||
drawMap(reponse['lap']);
|
||||
if(reponse['continue'] == '1'){
|
||||
play(gameId,xd_check);
|
||||
}
|
||||
|
||||
}else{
|
||||
|
||||
}
|
||||
}
|
||||
};
|
||||
req.open("POST", '/tron', true);
|
||||
req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
req.send('act=play&xd_check=' + xd_check + '&gameId=' + gameId + '&fullLogs=' + document.getElementById("fullLogs").checked);
|
||||
}
|
||||
function tron(xd_check){
|
||||
//empty
|
||||
while (document.getElementById('fightResult').firstChild) {
|
||||
document.getElementById('fightResult').removeChild(document.getElementById('fightResult').firstChild);
|
||||
}
|
||||
// draw border;
|
||||
var svg = createElemNS('svg',{'id':'map','width':'500','height':'500','viewBox':'0 0 1000 1000'});
|
||||
var rect=createElemNS('rect',{'x':'0','y':'0','width':'1000','height':'1000','style':'stroke:#000000; fill:none;'});
|
||||
svg.appendChild(rect);
|
||||
document.getElementById("fightResult").appendChild(svg);
|
||||
|
||||
var plogs = createElem("p",{'id':'logs'});
|
||||
document.getElementById("fightResult").appendChild(plogs);
|
||||
//get bot list
|
||||
var botsList=[];
|
||||
var i=0;
|
||||
while(document.getElementById('selectBot' + i)){
|
||||
botsList.push(document.getElementById('selectBot' + i).value);
|
||||
i++;
|
||||
}
|
||||
|
||||
//ask arena to send bots init messages
|
||||
var request = new XMLHttpRequest();
|
||||
request.onreadystatechange = function(){applyInitMessage(request,xd_check)};
|
||||
request.open("POST", '/tron', true);
|
||||
request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
request.send('act=initGame&xd_check=' + xd_check + '&bots=' + JSON.stringify(botsList) + '&fullLogs=' + document.getElementById("fullLogs").checked);
|
||||
}
|
32
src/arenas/tron/public.php
Normal file
32
src/arenas/tron/public.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
#- BEGIN LICENSE BLOCK ---------------------------------------
|
||||
#
|
||||
# This file is part of botsArena.
|
||||
#
|
||||
# Copyright (C) Gnieark et contributeurs
|
||||
# Licensed under the GPL version 3.0 license.
|
||||
# See LICENSE file or
|
||||
# http://www.gnu.org/licenses/gpl-3.0-standalone.html
|
||||
#
|
||||
# -- END LICENSE BLOCK -----------------------------------------
|
||||
|
||||
require_once(__DIR__."/functions.php");
|
||||
$bots=get_Bots_Array('tron');
|
||||
$botsArr=array();
|
||||
foreach($bots as $bot){
|
||||
$botsArr[]=array('id' => $bot['id'], 'name' => $bot['name']);
|
||||
}
|
||||
?>
|
||||
<article id="mainArticle">
|
||||
<h2><?php echo $lang['MAKE_DUEL'];?></h2>
|
||||
<aside id="configurePlayers">
|
||||
|
||||
</aside>
|
||||
<script>
|
||||
var botsAvailable = <?php echo json_encode($botsArr); ?>;
|
||||
show_bot_panel(0);
|
||||
</script>
|
||||
<p><input type="checkbox" id="fullLogs"/><label for="fullLogs">view the full logs</label></p>
|
||||
<p><input id="fightButton" disabled="disabled" type="button" value="<?php echo $lang['FIGHT']; ?>" onclick="tron('<?php echo xd_check_input(2); ?>');"></p>
|
||||
<div id="fightResult"></div>
|
||||
</article>
|
4
src/arenas/tron/style.css
Normal file
4
src/arenas/tron/style.css
Normal file
|
@ -0,0 +1,4 @@
|
|||
#configurePlayers{width: 100%;}
|
||||
#configurePlayers fieldset{display: block; width: 100px; float:left;}
|
||||
#logs{display:block;padding-left:10px; height: 200px; overflow-y: scroll;}
|
||||
#logs p em {color: grey; font-size: 70%; test-transform:italic;}
|
27
src/arenas/tron/test/CoordsTest.php
Normal file
27
src/arenas/tron/test/CoordsTest.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
use PHPUnit\Framework\TestCase;
|
||||
require_once '../Coords.php';
|
||||
require_once '../Direction.php';
|
||||
|
||||
class CoordsTest extends TestCase {
|
||||
|
||||
|
||||
public function testCirculaire(){
|
||||
$startCoord = new Coords(15,3);
|
||||
$endCoord = $startCoord->addDirection(Direction::make('x+'))
|
||||
->addDirection(Direction::make('y-'))
|
||||
->addDirection(Direction::make('x-'))
|
||||
->addDirection(Direction::make('y+'));
|
||||
|
||||
|
||||
|
||||
$this->assertTrue($endCoord == $startCoord);
|
||||
}
|
||||
public function testIsDifferent(){
|
||||
$startCoord = new Coords(15,3);
|
||||
$endCoord = $startCoord->addDirection(Direction::make('x+'));
|
||||
fwrite(STDERR, $startCoord ."\n");
|
||||
fwrite(STDERR, $endCoord ."\n");
|
||||
$this->assertFalse($endCoord == $startCoord);
|
||||
}
|
||||
}
|
71
src/arenas/tron/test/DirectionTest.php
Normal file
71
src/arenas/tron/test/DirectionTest.php
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
use PHPUnit\Framework\TestCase;
|
||||
require_once '../Direction.php';
|
||||
|
||||
class Directiontest extends TestCase {
|
||||
public function invalidStrings() {
|
||||
return array(
|
||||
array('jhgjhg'),
|
||||
array('X+'),
|
||||
array(4)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @dataProvider invalidStrings
|
||||
* @expectedException invalidDirectionException
|
||||
*/
|
||||
public function testRejectInvalidString($invalidString){
|
||||
Direction::make($invalidString);
|
||||
}
|
||||
public function validStrings(){
|
||||
return array(
|
||||
array('x+'),
|
||||
array('y+'),
|
||||
array('x-'),
|
||||
array('y-'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider validStrings
|
||||
*/
|
||||
public function testAcceptValidString($validString){
|
||||
$this->assertInstanceOf(Direction::class,Direction::make($validString));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider validStrings
|
||||
*/
|
||||
public function testDeltaXY($validString){
|
||||
$dir = Direction::make($validString);
|
||||
$this->assertTrue($dir->deltaX != 0 || $dir->deltaY != 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider validStrings
|
||||
*/
|
||||
public function testToString($validString){
|
||||
$this->assertTrue(Direction::make($validString) == $validString);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider validStrings
|
||||
*/
|
||||
public function testOpposite($validString){
|
||||
$dir = Direction::make($validString);
|
||||
$op = $dir->opposite();
|
||||
|
||||
$this->assertInstanceOf(Direction::class,$op);
|
||||
$this->assertFalse($dir == $op);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider validStrings
|
||||
*/
|
||||
public function testOppositeOpposite($validString){
|
||||
$dir = Direction::make($validString);
|
||||
$opop = $dir->opposite()->opposite();
|
||||
$this->assertTrue($dir == $opop);
|
||||
}
|
||||
|
||||
}
|
64
src/arenas/tron/test/TrailTest.php
Normal file
64
src/arenas/tron/test/TrailTest.php
Normal file
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
require_once '../Direction.php';
|
||||
require_once '../Coords.php';
|
||||
require_once '../TronPlayer.php';
|
||||
|
||||
class TronPlayerTest extends TestCase {
|
||||
public function validPlayer(Direction $direction) {
|
||||
return new TronPlayer(
|
||||
'http://127.0.0.1',
|
||||
'test',
|
||||
new Coords(0, 0),
|
||||
$direction
|
||||
);
|
||||
}
|
||||
|
||||
public function testTronPlayerCreation() {
|
||||
$this->assertInstanceOf(
|
||||
TronPlayer::class,
|
||||
$this->validPlayer(Direction::make('x+'))
|
||||
);
|
||||
}
|
||||
|
||||
public function directions() {
|
||||
return array(
|
||||
array(Direction::make('x+')),
|
||||
array(Direction::make('x-')),
|
||||
array(Direction::make('y+')),
|
||||
array(Direction::make('y-')),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider directions
|
||||
* @expectedException OppositeForbiddenException
|
||||
*/
|
||||
public function testOppositeForbidden(Direction $direction) {
|
||||
$player = $this->validPlayer($direction);
|
||||
$player->changeDirection($direction->opposite());
|
||||
}
|
||||
|
||||
public function testAlreadyLost() {
|
||||
$right = Direction::make('x+');
|
||||
$down = Direction::make('y-');
|
||||
$left = Direction::make('x-');
|
||||
$up = Direction::make('y+');
|
||||
|
||||
$player = $this->validPlayer($right);
|
||||
$player->nextMove($right);
|
||||
$player->nextMove($down);
|
||||
$player->nextMove($left);
|
||||
|
||||
try {
|
||||
$player->nextMove($up);
|
||||
throw new Exception('TronPlayer did not throw AlreadyPlayedException');
|
||||
} catch(AlreadyPlayedException $e) { }
|
||||
|
||||
try {
|
||||
$player->nextMove($up);
|
||||
throw new Exception('TronPlayer did not throw AlreadyLostException');
|
||||
} catch(AlreadyLostException $e) { }
|
||||
}
|
||||
}
|
|
@ -36,6 +36,14 @@ $arenas=array(
|
|||
'jsFile'=> "js.js",
|
||||
'cssFile'=> "style.css",
|
||||
'ludusUrl' => "/testBotScripts/connectfour.html"
|
||||
),
|
||||
array(
|
||||
'id' => "tron",
|
||||
'url' => "/tron",
|
||||
'title' => "Tron",
|
||||
'metaDescription' => 'Affrontements de bots à Tron',
|
||||
'jsFile'=> "js.js",
|
||||
'cssFile'=> "style.css"
|
||||
)
|
||||
|
||||
);
|
|
@ -151,7 +151,7 @@ function conn_bdd(){
|
|||
}
|
||||
mysqli_select_db($linkMysql,$mysqlParams['database']);
|
||||
mysqli_set_charset($linkMysql, 'utf8');
|
||||
return $linkMysql; //does PHP can do that?
|
||||
return $linkMysql;
|
||||
|
||||
}
|
||||
function get_battles_history($game){
|
||||
|
@ -229,18 +229,24 @@ function ELO_get_new_ranks($elo1,$elo2,$score){
|
|||
$elo2 + ELO_get_k($elo2) * (1 - $score - (1/ (1 + pow(10,(($elo1 - $elo2) / 400)))))
|
||||
);
|
||||
}
|
||||
function save_battle($game,$bot1,$bot2,$resultat){
|
||||
|
||||
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
|
||||
|
||||
global $lnMysql;
|
||||
|
||||
$game=substr($game,0,8); //limit 8 char for limitting mysql index size
|
||||
|
||||
|
||||
//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"){
|
||||
//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)."'");
|
||||
}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];
|
||||
|
@ -381,4 +387,4 @@ function get_IA_Response($iaUrl,$postParams){
|
|||
'response' => $output,
|
||||
'responseArr' => $arr
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user