Artykuły na każdy temat
<?php
# MySQL
$config['mysql']['host'] = 'localhost'; // Host of database
$config['mysql']['database'] = 'wotstats'; // Name of database
$config['mysql']['login'] = ''; // Login to database
$config['mysql']['password'] = ''; // Password to database
# Other informations
$config['send_request']['protocol'] = 'http://';
$config['send_request']['resource_path'] = 'wot';
?>
Natomiast plik update_wnexpected_tank_values.php wygląda tak:
<?php
// Include necessary things
require './config.php';
require './wot.class.php';
// Execute the application
$wot = new wot($config, 'eu');
var_dump($wot -> update_wnexpected_tank_values_table());
?>
Najlepszym rozwiązaniem aby dane były aktualne jest uruchamianie tego skryptu cyklicznie przy pomocy CRON'a. Aby całość funkcjonowała potrzebujemy oczywiście także wot.class.php:
<?php
/**
* @package Wotstats
* @subpackage Core
* @author CapaciousCore
* @copyright Copyright (C) 2014-2015 CapaciousCore
*/
class wot
{
private $db;
private $config;
private $wnexpected_tank_values;
public function wot($config, $server)
{
// Set up config
$this -> config = $config;
$this -> config['server'] = $server;
$this -> set_server_domain();
$this -> set_api_url();
$this -> db = new mysqli($this -> config['mysql']['host'], $this -> config['mysql']['login'], $this -> config['mysql']['password'], $this -> config['mysql']['database']);
unset($this -> config['mysql']);
if($this -> db -> connect_errno !== 0)
{
throw new Exception('Could not connect to database');
}
else
{
$this -> db -> set_charset('utf8');
}
}
public function update_wnexpected_tank_values_table($force_update = false)
{
$stmt = $this -> db -> prepare('SELECT MAX(version) as version FROM wnexpected_tank_values');
$stmt -> execute();
$stmt -> store_result();
$stmt -> bind_result($current_version);
$stmt -> fetch();
$wnexpected_tank_values_table = json_decode(file_get_contents('http://www.wnefficiency.net/exp/expected_tank_values_latest.json'));
$source_version = $wnexpected_tank_values_table -> header -> version;
if($wnexpected_tank_values_table !== null)
{
if($force_update === true || $source_version > $current_version)
{
$stmt = $this -> db -> prepare('INSERT INTO wnexpected_tank_values VALUES (?, ?, ?, ?, ?, ?, ?)');
$this -> db -> autocommit(false);
foreach($wnexpected_tank_values_table -> data as $tank_values_table)
{
$stmt -> bind_param('iiddddd', $source_version, $tank_values_table -> IDNum, $tank_values_table -> expFrag, $tank_values_table -> expDamage, $tank_values_table -> expSpot, $tank_values_table -> expDef, $tank_values_table -> expWinRate);
$stmt -> execute();
if($stmt -> errno !== 0 && $stmt -> errno !== 1062)
{
// Log this fail!
// var_dump($stmt -> errno, $stmt -> error);
$is_failed = true;
break;
}
}
if($this -> db -> commit() === false)
{
$this -> db -> rollback();
$is_failed = true;
}
$this -> db -> autocommit(true);
}
}
else
{
$is_failed = true;
}
return $is_failed === null;
}
private function get_wnexpected_tank_values_table($version = null)
{
// $version = null means current version
$stmt = $this -> db -> prepare('SELECT tank_id, ROUND(expected_kills, 2), ROUND(expected_damage, 2), ROUND(expected_detections, 2), ROUND(expected_defense, 2), ROUND(expected_winrate, 2) FROM wnexpected_tank_values WHERE version = '.($version === null ? '(SELECT MAX(version) FROM wnexpected_tank_values)' : $version).' ORDER BY tank_id');
$stmt -> execute();
$stmt -> bind_result($tank_id, $expected_kills, $expected_damage, $expected_detections, $expected_defense, $expected_winrate);
while($stmt -> fetch())
{
$wnexpected_tank_values[$tank_id] = array($expected_kills, $expected_damage, $expected_detections, $expected_defense, $expected_winrate);
}
return $wnexpected_tank_values;
}
private function send_request($address, $query = array(), $stop_upon_crash = false)
{
// It's just a prototype method that should be improved about error handling even
$url = $this -> config['api_url'].$address.'/?application_id=demo&'.http_build_query($query);
while(1)
{
// I recommend use curl library
$data = file_get_contents($url);
if($data !== false)
{
$data = json_decode($data);
if($data -> status === 'ok')
{
return $data;
}
else if($stop_upon_crash === true && $data -> status === 'error')
{
return $data;
}
}
sleep(1);
}
}
private function set_server_domain()
{
$this -> config['domain'] = ($this -> config['server'] === 'na' ? 'com' : $this -> config['server']);
}
private function set_api_url()
{
$this -> config['api_url'] = $this -> config['send_request']['protocol'].'api.worldoftanks.'.$this -> config['domain'].'/';
}
public function wn8($account_id, $as_fraction = false, $calculate_for_each_tank = false, $list_of_tanks = null)
{
if($this -> wnexpected_tank_values === null)
{
$this -> wnexpected_tank_values = $this -> get_wnexpected_tank_values_table();
}
$data = $this -> send_request('wot/tanks/stats', array('account_id' => $account_id, 'fields' => 'tank_id,all.battles,all.frags,all.damage_dealt,all.spotted,all.dropped_capture_points,all.wins')) -> data -> {$account_id};
if($data !== null)
{
// Step 1
foreach($data as $vehicle_info)
{
if($this -> wnexpected_tank_values[$vehicle_info -> tank_id] !== null)
{
// Forewarned is forearmed
if($vehicle_info -> all -> battles > 0)
{
// Calculate it!
$battles += $vehicle_info -> all -> battles;
$exp_frag[$vehicle_info -> tank_id] = $this -> wnexpected_tank_values[$vehicle_info -> tank_id][0] * $vehicle_info -> all -> battles;
$exp_dmg[$vehicle_info -> tank_id] = $this -> wnexpected_tank_values[$vehicle_info -> tank_id][1] * $vehicle_info -> all -> battles;
$exp_spot[$vehicle_info -> tank_id] = $this -> wnexpected_tank_values[$vehicle_info -> tank_id][2] * $vehicle_info -> all -> battles;
$exp_def[$vehicle_info -> tank_id] = $this -> wnexpected_tank_values[$vehicle_info -> tank_id][3] * $vehicle_info -> all -> battles;
$exp_wins[$vehicle_info -> tank_id] = $this -> wnexpected_tank_values[$vehicle_info -> tank_id][4] * $vehicle_info -> all -> battles * 0.01;
// Additional necessary statistics
$account_statistics['frags'][$vehicle_info -> tank_id] = $vehicle_info -> all -> frags;
$account_statistics['damage_dealt'][$vehicle_info -> tank_id] = $vehicle_info -> all -> damage_dealt;
$account_statistics['spotted'][$vehicle_info -> tank_id] = $vehicle_info -> all -> spotted;
$account_statistics['dropped_capture_points'][$vehicle_info -> tank_id] = $vehicle_info -> all -> dropped_capture_points;
$account_statistics['wins'][$vehicle_info -> tank_id] = $vehicle_info -> all -> wins;
}
}
// Tank missing in expected tank values table so add it to the list
else
{
// Log this ids!
// $missing_tanks_ids[] = $vehicle_info -> tank_id;
}
}
if($battles > 0)
{
if($calculate_for_each_tank === true XOR $list_of_tanks !== null)
{
foreach(($list_of_tanks !== null ? $list_of_tanks : array_keys($exp_frag)) as $tank_id)
{
if($list_of_tanks === null || $list_of_tanks !== null && $exp_frag[$tank_id] !== null)
{
// Step 2
$r_frag = $account_statistics['frags'][$tank_id] / $exp_frag[$tank_id];
$r_dmg = $account_statistics['damage_dealt'][$tank_id] / $exp_dmg[$tank_id];
$r_spot = $account_statistics['spotted'][$tank_id] / $exp_spot[$tank_id];
$r_def = $account_statistics['dropped_capture_points'][$tank_id] / $exp_def[$tank_id];
$r_wins = $account_statistics['wins'][$tank_id] / $exp_wins[$tank_id];
// Step 3
$r_dmg_c = max(0, ($r_dmg - 0.22) / (1 - 0.22));
$r_frag_c = max(0, min($r_dmg_c + 0.2, ($r_frag - 0.12) / (1 - 0.12)));
$r_spot_c = max(0, min($r_dmg_c + 0.1, ($r_spot - 0.38) / (1 - 0.38)));
$r_def_c = max(0, min($r_dmg_c + 0.1, ($r_def - 0.10) / (1 - 0.10)));
$r_wins_c = max(0, ($r_wins - 0.71) / (1 - 0.71));
// Discovered the holy grail! Calculate the WN8
$wn8[$tank_id] = 980 * $r_dmg_c + 210 * $r_dmg_c * $r_frag_c + 155 * $r_frag_c * $r_spot_c + 75 * $r_def_c * $r_frag_c + 145 * min(1.8, $r_wins_c);
$wn8[$tank_id] = round($wn8[$tank_id], ($as_fraction === true ? 2 : 0));
if($as_fraction === false)
{
$wn8[$tank_id] = (int)$wn8[$tank_id];
}
}
}
}
// Step 2 (overall)
$r_frag = array_sum($account_statistics['frags']) / array_sum($exp_frag);
$r_dmg = array_sum($account_statistics['damage_dealt']) / array_sum($exp_dmg);
$r_spot = array_sum($account_statistics['spotted']) / array_sum($exp_spot);
$r_def = array_sum($account_statistics['dropped_capture_points']) / array_sum($exp_def);
$r_wins = array_sum($account_statistics['wins']) / array_sum($exp_wins);
// Step 3 (overall)
$r_dmg_c = max(0, ($r_dmg - 0.22) / (1 - 0.22));
$r_frag_c = max(0, min($r_dmg_c + 0.2, ($r_frag - 0.12) / (1 - 0.12)));
$r_spot_c = max(0, min($r_dmg_c + 0.1, ($r_spot - 0.38) / (1 - 0.38)));
$r_def_c = max(0, min($r_dmg_c + 0.1, ($r_def - 0.10) / (1 - 0.10)));
$r_wins_c = max(0, ($r_wins - 0.71) / (1 - 0.71));
// Discovered the holy grail! Calculate the WN8 (overall)
$wn8['overall'] = (980 * $r_dmg_c) + (210 * $r_dmg_c * $r_frag_c) + (155 * $r_frag_c * $r_spot_c) + (75 * $r_def_c * $r_frag_c) + (145 * min(1.8, $r_wins_c));
$wn8['overall'] = round($wn8['overall'], ($as_fraction === true ? 2 : 0));
if($as_fraction === false)
{
$wn8['overall'] = (int)$wn8['overall'];
}
// Return our mighty number
return ($calculate_for_each_tank === false && $list_of_tanks === null ? $wn8['overall'] : $wn8);
}
}
return null;
}
}
?>
Dodatkowo potrzebna będzie nam tabela wnexpected_tank_values, którą zbudujemy przy pomocy poniższego zapytania:
CREATE TABLE IF NOT EXISTS `wnexpected_tank_values` (
`version` tinyint(1) unsigned NOT NULL,
`tank_id` smallint(1) unsigned NOT NULL,
`expected_kills` float unsigned NOT NULL,
`expected_damage` float unsigned NOT NULL,
`expected_detections` float unsigned NOT NULL,
`expected_defense` float unsigned NOT NULL,
`expected_winrate` float unsigned NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
ALTER TABLE `wnexpected_tank_values` ADD PRIMARY KEY (`version`,`tank_id`);
Szukając po sieci rozwiązań odnośnie obliczania WN8 natrafiałem jedynie na karykatury lub mizerne i nieoptymalne próby obliczania tego współczynnika. W związku z tym postanowiłem napisać to osobiście. Efekt mojej pracy można zobaczyć w listingu powyżej. Aby obliczyć WN8 danego gracza wywołujemy calculate_wn8.php, który wygląda następująco:
<?php
// Include necessary things
require './config.php';
require './wot.class.php';
// Execute the application
$wot = new wot($config, 'eu');
var_dump($wot -> wn8(509459275)); // Pinkman_Jesse - supposedly the best player on the european server World of Tanks
?>
Oczywiście prezentowany kod jest tylko przykładem jak i fragmentem większej układanki. Układanki na którą składa się wiele plików i klas robota sieciowego jednak ja uznałem, że podam tylko to co niezbędne. Polecam również poeksperymentować z argumentami przy metodzie wn8(). A jako ciekawostkę powiem, że deweloperzy pracują już formułą WN9. Ponadto znając algorytm i będąc rozgarniętą osobą można manipulować tą statystyką.
Komentarze
Dodaj komentarz