PHP Classes

File: api.php

Recommend this page to a friend!
  Classes of Aleksey   PHP Football Simulation   api.php   Download  
File: api.php
Role: Example script
Content type: text/plain
Description: Example script
Class: PHP Football Simulation
Compute football teams attack and defense strength
Author: By
Last change:
Date: 6 years ago
Size: 7,258 bytes
 

Contents

Class file image Download
<?php
/*
 * Copyright (c) 2017 @meet-aleksey <https://github.com/meet-aleksey>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
 
Error('POST request method is expected.');
  return;
}

// get request body:
$requestBody = file_get_contents('php://input');

// check type of content:
if (strrpos($_SERVER['HTTP_CONTENT_TYPE'], '/json') !== FALSE || strrpos($_SERVER['CONTENT_TYPE'], '/json') !== FALSE) {
 
// json:
 
$query = json_decode($requestBody, true);
} else {
 
// file:
 
$query = array('method' => 'upload');
}

if (empty(
$query['method'])) {
 
Error('The "method" is required. Value cannot be empty.');
  return;
}

require_once
'team.php';
require_once
'match.php';
require_once
'stage.php';

switch (
strtolower($query['method'])) {
  case
'example':
   
// return example data:
   
OutputExampleData();
    break;

  case
'simulate':
   
// return results of simulation:
   
OutputSimulationResult($query['teams']);
    break;

  case
'upload':
   
OutputData($requestBody);
    break;

  default:
   
Error('Unknown method.');
    break;
}

/**
 * Gets data from data.csv.
 *
 * @return void
 */
function OutputExampleData() {
  if ((
$data = file_get_contents('data.csv')) !== FALSE) {
   
OutputData($data);
  }
  else {
   
Error('Cannot open file data.csv. Check the existence of "data.csv" and the permission to read it.');
  }
}

/**
 * Outputs the specified data.
 *
 * @param string $data
 * CSV data to parse and output.
 *
 * @return void
 */
function OutputData($data) {
  if (empty(
$data)) {
   
Error('Data is required.');
    return;
  }

 
$skip = TRUE;
 
$teams = array();

 
$total = new Team();
 
$total->Name = 'Total';
 
$total->Games = $total->Goals = $total->Losses =
 
$total->Missed = $total->Draw = $total->Wins = 0;

 
$rows = split("\n", preg_replace('~\R~u', "\n", $data));

  foreach (
$rows as $row) {
    if (empty(
$row)) {
      continue;
    }

   
$row = str_getcsv($row, ';');

    if (
count($row) < 6) {
     
Error('Wrong data. Please check the file format.');
      return;
    }

    if (
$skip) {
     
$skip = FALSE;
      continue;
    }

   
$team = new Team();

   
$team->Name = trim($row[0]);
   
$total->Games += ($team->Games = (int)$row[1]);
   
$total->Wins += ($team->Wins = (int)$row[2]);
   
$total->Losses += ($team->Losses = (int)$row[3]);
   
$total->Draw += ($team->Draw = (int)$row[4]);

   
$balls = split('-', $row[5]);

   
$total->Goals += ($team->Goals = (int)trim($balls[0]));
   
$total->Missed += ($team->Missed = (int)trim($balls[1]));

   
// add team to list
   
$teams[] = $team;
  }

 
// add total results
 
$teams[] = $total;

 
Output($teams);
}

/**
 * Outputs simulations result.
 *
 * @param array $teams
 * List of teams.
 *
 * @return void
 */
function OutputSimulationResult($teams) {
 
$result = array();

 
Play($result, $teams);
 
Output($result);
}

/**
 * Simulates a stage of football matches.
 *
 * @param Stage[] &$writer
 * List of stages for output.
 *
 * @param array $teams
 * List of teams.
 *
 * @param int $stageNumber
 * Stage number. Default: 1.
 *
 * @return void
 */
function Play(&$writer, $teams, $stageNumber = 1) {
  if (!isset(
$stageNumber)) {
   
$stageNumber = 1;
  }

 
// create new stage:
 
$writer[] = $stage = new Stage();
 
$stage->Matches = array();

 
// teams count:
 
$totalTeams = count($teams);

 
// mix the array:
 
shuffle($teams);

 
// losers to remove:
 
$losers = array();

 
// simulate
 
for ($i = 0; $i < $totalTeams; $i += 2) {
   
$goalsAvg = array(
     
$teams[$i]['Goals'] / $teams[$i]['Games'],
     
$teams[$i + 1]['Goals'] / $teams[$i + 1]['Games']
    );
   
$missedAvg = array(
     
$teams[$i]['Missed'] / $teams[$i]['Games'],
     
$teams[$i + 1]['Missed'] / $teams[$i + 1]['Games']
    );

   
$stage->Matches[] = $match = new Match();

   
$match->Teams = array($teams[$i]['Name'], $teams[$i + 1]['Name']);
   
$match->Results = array(
     
Poisson(
        (
$goalsAvg[0] / $missedAvg[0]) * ($missedAvg[0] / $goalsAvg[0]) * $goalsAvg[0],
        (
$goalsAvg[1] / $missedAvg[1]) * ($missedAvg[1] / $goalsAvg[1]) * $goalsAvg[1]
      ),
     
Poisson(
        (
$goalsAvg[1] / $missedAvg[1]) * ($missedAvg[1] / $goalsAvg[1]) * $goalsAvg[1],
        (
$goalsAvg[0] / $missedAvg[0]) * ($missedAvg[0] / $goalsAvg[0]) * $goalsAvg[0]
      )
    );

    if (
$match->Results[0] > $match->Results[1]) {
     
$losers[] = $teams[$i + 1]['Name'];
    }
    else if (
$match->Results[1] > $match->Results[0]) {
     
$losers[] = $teams[$i]['Name'];
    }
    else {
     
$losers[] = $teams[rand($i, $i + 1)]['Name'];
    }
  }

 
// names of all teams to search index by name:
 
$namesOfAllTeams = array_map(function($itm) { return $itm['Name']; }, $teams);

 
// remove losers:
 
foreach ($losers as $teamName) {
    if ((
$index = array_search($teamName, $namesOfAllTeams)) !== FALSE) {
      unset(
$teams[$index]);
    }
  }

 
// next stage:
 
if (count($teams) >= 2) {
   
Play($writer, $teams, $stageNumber + 1);
  }
}

/**
 * Calculates factorial.
 *
 * @param double|integer $number
 *
 * @return double|integer
 */
function Factorial($number)
{
  if (
$number < 2) {
    return
1;
  } else {
    return (
$number * Factorial($number - 1));
  }
}

/**
 * Poisson Distribution.
 *
 * @param mixed $chance
 * The probability value.
 *
 * @param mixed $occurrence
 * The number of occurances.
 *
 * @return double
 */
function Poisson($chance, $occurrence)
{
  return
round((exp(-$chance) * pow($chance, $occurrence) / Factorial($occurrence)) * 100, 2);
}

/**
 * Outputs error message.
 *
 * @param string $message
 * Text of error message.
 *
 * @return void
 */
function Error($message) {
 
Output(array('Error' => array('Text' => $message)), 500);
}

/**
 * Outputs response.
 *
 * @param mixed $data
 * Data to output.
 *
 * @param int $status
 * The HTTP status code. Default: 200 (OK).
 *
 * @return void
 */
function Output($data, $status = 200) {
 
header('Content-Type: application/json');
 
http_response_code($status);

 
$result = json_encode($data);

  if (
$result === FALSE)
  {
    throw new
ErrorException('JSON encode error #' . json_last_error() . ': ' . json_last_error_msg());
  }

  echo
$result;
}