221 lines
5.5 KiB
PHP
221 lines
5.5 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace Drupal\ufc\Controller;
|
||
|
|
|
||
|
|
use Drupal\Core\Controller\ControllerBase;
|
||
|
|
use Drupal\Core\Entity\EntityTypeManager;
|
||
|
|
use Drupal\node\NodeInterface;
|
||
|
|
use Drupal\node\Entity\Node;
|
||
|
|
use Drupal\media\Entity\Media;
|
||
|
|
use Drupal\file\Entity\File;
|
||
|
|
use Drupal\Core\Cache\CacheableJsonResponse;
|
||
|
|
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||
|
|
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||
|
|
use Symfony\Component\HttpFoundation\Request;
|
||
|
|
|
||
|
|
class FightTrainingController extends ControllerBase {
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Fields holding fighter data.
|
||
|
|
*/
|
||
|
|
protected $fields = [
|
||
|
|
'age',
|
||
|
|
'height',
|
||
|
|
'reach',
|
||
|
|
'leg_reach',
|
||
|
|
'knockouts',
|
||
|
|
'striking_accuracy',
|
||
|
|
'strikes_per_minute',
|
||
|
|
'sig_strike_defense',
|
||
|
|
'absorbed_per_min',
|
||
|
|
'standing_strikes',
|
||
|
|
'clinch_strikes',
|
||
|
|
'ground_strikes',
|
||
|
|
'grappling_accuracy',
|
||
|
|
'strikes_to_head',
|
||
|
|
'strikes_to_body',
|
||
|
|
'strikes_to_leg',
|
||
|
|
'knockdown_ratio',
|
||
|
|
'takedowns_per_15',
|
||
|
|
'takedown_defense',
|
||
|
|
'average_fight_time',
|
||
|
|
'first_round_finishes',
|
||
|
|
];
|
||
|
|
|
||
|
|
/**
|
||
|
|
* The entity type manager service.
|
||
|
|
*
|
||
|
|
* @var Drupal\Core\Entity\EntityTypeManager
|
||
|
|
* The entity type manager service.
|
||
|
|
*/
|
||
|
|
protected $entityTypeManager;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Public constructor.
|
||
|
|
*
|
||
|
|
* @var \Drupal\Core\Entity\EntityTypeManager $entityTypeManager
|
||
|
|
* The entity type manager service.
|
||
|
|
*
|
||
|
|
*/
|
||
|
|
public function __construct(
|
||
|
|
EntityTypeManager $entityTypeManager
|
||
|
|
) {
|
||
|
|
$this->entityTypeManager = $entityTypeManager;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* {@inheritdoc}
|
||
|
|
*/
|
||
|
|
public static function create(ContainerInterface $container) {
|
||
|
|
// Instantiates this form class.
|
||
|
|
return new static(
|
||
|
|
// Load the service required to construct this class.
|
||
|
|
$container->get('entity_type.manager'),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Generates all fighting data for training NN.
|
||
|
|
*/
|
||
|
|
public function generateTrainingData(): CacheableJsonResponse {
|
||
|
|
// Go get all fights.
|
||
|
|
$all_fights = $this->entityTypeManager->getStorage('node')->loadByProperties(['type' => 'fight']);
|
||
|
|
$training_data = [];
|
||
|
|
foreach ($all_fights as $fight) {
|
||
|
|
$train_array = [
|
||
|
|
'input' => [],
|
||
|
|
'output' => [],
|
||
|
|
];
|
||
|
|
// Ensure we have a winner.
|
||
|
|
if (!$fight->field_result->target_id) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
// Extract fighters.
|
||
|
|
$fighter_one_id = $fight->field_fighter_one->target_id;
|
||
|
|
$fighter_two_id = $fight->field_fighter_two->target_id;
|
||
|
|
|
||
|
|
if (!$fighter_one_id || !$fighter_two_id) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$fighter_one_data = $this->getFighterData($fighter_one_id);
|
||
|
|
$fighter_two_data = $this->getFighterData($fighter_two_id, FALSE);
|
||
|
|
|
||
|
|
if (empty($fighter_one_data) || empty($fighter_two_data)) {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$train_array['input'] = array_merge($fighter_one_data, $fighter_two_data);
|
||
|
|
|
||
|
|
if ($fight->field_result->target_id == $fighter_one_id) {
|
||
|
|
$train_array['output'] = [
|
||
|
|
'fighter_one' => 1,
|
||
|
|
'fighter_two' => 0,
|
||
|
|
];
|
||
|
|
$training_data[] = $train_array;
|
||
|
|
}
|
||
|
|
else if ($fight->field_result->target_id == $fighter_two_id) {
|
||
|
|
$train_array['output'] = [
|
||
|
|
'fighter_one' => 0,
|
||
|
|
'fighter_two' => 1,
|
||
|
|
];
|
||
|
|
$training_data[] = $train_array;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return new CacheableJsonResponse($training_data);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Retrieves data about a specific fight for predictions.
|
||
|
|
*/
|
||
|
|
public function getFightData(NodeInterface $fight): CacheableJsonResponse {
|
||
|
|
$fighter_1_id = $fight->field_fighter_one->target_id;
|
||
|
|
$fighter_2_id = $fight->field_fighter_two->target_id;
|
||
|
|
|
||
|
|
$fight_data = array_merge(
|
||
|
|
$this->getFighterData($fighter_1_id),
|
||
|
|
$this->getFighterData($fighter_2_id, FALSE),
|
||
|
|
);
|
||
|
|
|
||
|
|
return new CacheableJsonResponse($fight_data);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Gets the fighter data.
|
||
|
|
*
|
||
|
|
* @return array<string,mixed>
|
||
|
|
*/
|
||
|
|
private function getFighterData(int $id, bool $is_f1 = TRUE): array {
|
||
|
|
if ($is_f1) {
|
||
|
|
$prefix = 'fighter_one_';
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
$prefix = 'fighter_two_';
|
||
|
|
}
|
||
|
|
|
||
|
|
$extracted_values = $this->extractValuesFromFields($id, $this->fields, $prefix);
|
||
|
|
|
||
|
|
return $this->normalizeData($extracted_values);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Extracts a value from a given field (cannot be ent reference)
|
||
|
|
*/
|
||
|
|
private function extractValuesFromFields(int $id, array $field_names, string $prefix): mixed {
|
||
|
|
$fighter = Node::load($id);
|
||
|
|
$values = [];
|
||
|
|
|
||
|
|
foreach ($field_names as $field) {
|
||
|
|
$value_key = $prefix . $field;
|
||
|
|
$field_machine_name = 'field_' . $field;
|
||
|
|
$values[$value_key] = $fighter->{$field_machine_name}->value ?? 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
return $values;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Normalize the field value.
|
||
|
|
*
|
||
|
|
* This needs to be between 0-1
|
||
|
|
*/
|
||
|
|
private function normalizeData(array $data): array {
|
||
|
|
$min = min(array_values($data));
|
||
|
|
$max = max(array_values($data));
|
||
|
|
$normalized = [];
|
||
|
|
foreach ($data as $key => $value) {
|
||
|
|
$norm_val = 0;
|
||
|
|
if ($max - $min == 0) {
|
||
|
|
$normalized[$key] = $norm_val;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
$norm_val = ($value - $min) / ($max - $min);
|
||
|
|
$normalized[$key] = $norm_val;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $normalized;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Gets the trained neural network.
|
||
|
|
*/
|
||
|
|
public function getNeuralNetwork(): CacheableJsonResponse {
|
||
|
|
$build = [];
|
||
|
|
$cur_network = \Drupal::state()->get('neuralNetwork') ?? FALSE;
|
||
|
|
if (!$cur_network) {
|
||
|
|
$build['ERROR'] = "There is no spoon.";
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
$build['data'] = base64_decode($cur_network);
|
||
|
|
}
|
||
|
|
|
||
|
|
return new CacheableJsonResponse($build);
|
||
|
|
}
|
||
|
|
|
||
|
|
}
|