PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/src/engine.php

https://bitbucket.org/lothario/fifa-tourny
PHP | 555 lines | 385 code | 117 blank | 53 comment | 48 complexity | 0f33d985967f4a6c4196ad7f29c74fe4 MD5 | raw file
  1. <?php
  2. //Setup variables
  3. $finalTeams = 32;
  4. $finalTeamsPerGroup = 4;
  5. $qualTeamsPerGroup = 4;
  6. $seedStart = 0.7;
  7. $seedInterval = 0.1;
  8. $seedEnd = 0.1;
  9. //Load mysql
  10. $dbhost = 'HOST';
  11. $dbname = 'NAME';
  12. $dbuser = 'USER';
  13. $dbpasswd = 'PASSWORD';
  14. //Switch to localhost, if applicaple
  15. $whitelist = array('localhost', '127.0.0.1');
  16. if(in_array($_SERVER['HTTP_HOST'], $whitelist)){
  17. $dbhost = 'localhost';
  18. }
  19. //Connect to database
  20. $db = new mysql_db($dbname, $dbhost, $dbuser, $dbpasswd);
  21. //Fetch all teams, ordered
  22. $sql = "SELECT * FROM fifa_teams
  23. ORDER BY stage, team_rating DESC, team_sort";
  24. $db->query($sql);
  25. while($row = mysql_fetch_array($db->result))
  26. {
  27. $teams[$row['team_id']] = $row;
  28. }
  29. $totalTeams = count($teams);
  30. //Make sure the final amount of teams are not larger than the total amount of teams
  31. if($totalTeams < $finalTeams)
  32. {
  33. $finalTeams = $totalTeams;
  34. }
  35. //Calculate competition structure
  36. $stages = knockoutStructure($totalTeams, $finalTeams, $seedStart, $seedInterval, $seedEnd);
  37. $qualifiedTeams = array();
  38. $seededTeams = array();
  39. $stageGroups = array();
  40. //Amount of stages
  41. $numStages = count($stages);
  42. if(isset($_GET['logout']) && $_GET['logout']=='true')
  43. {
  44. // Unset all of the session variables.
  45. $_SESSION = array();
  46. // If it's desired to kill the session, also delete the session cookie.
  47. // Note: This will destroy the session, and not just the session data!
  48. if (ini_get("session.use_cookies")) {
  49. $params = session_get_cookie_params();
  50. setcookie(session_name(), '', time() - 42000,
  51. $params["path"], $params["domain"],
  52. $params["secure"], $params["httponly"]
  53. );
  54. }
  55. // Finally, destroy the session.
  56. session_destroy();
  57. header('Location: ./index.php');
  58. }
  59. if(isset($_GET['reset']) && $_GET['reset'] == 'true')
  60. {
  61. $reset = true;
  62. }
  63. else
  64. {
  65. $reset = false;
  66. }
  67. for($i = 1; $i <= $numStages; $i++)
  68. {
  69. $seededTeams[$i] = array();
  70. $qualifiedTeams[$i] = array();
  71. }
  72. //If stages are not set (or on reset), place seeded teams in each stage
  73. if(($reset || $db->exists('fifa_teams', 'stage = 0')) && $logged_in)
  74. {
  75. //Clear stages and reselect teams
  76. $sql_data = array();
  77. $teams = array();
  78. $sql_data[] = array(
  79. 'stage' => 0,
  80. 'qualified' => 0,
  81. 'groupNo' => 0
  82. );
  83. if(!$db->update('fifa_teams', $sql_data, ''))
  84. {
  85. echo $db->error();
  86. exit();
  87. }
  88. $sql = 'TRUNCATE fifa_matches';
  89. $db->query($sql);
  90. //Fetch all teams, ordered
  91. $sql = "SELECT * FROM fifa_teams
  92. ORDER BY team_rating DESC, team_sort";
  93. $db->query($sql);
  94. while($row = mysql_fetch_array($db->result))
  95. {
  96. $teams[$row['team_id']] = $row;
  97. }
  98. //Seed teams, and place them in the correct stage
  99. foreach(array_reverse($stages, true) as $id => $stage)
  100. {
  101. $seededTeams[$id] = array();
  102. for($i=1; $i<= $stage['seeded']; $i++)
  103. {
  104. $seededTeam = array_shift($teams);
  105. $seededTeams[$id][$seededTeam['team_id']] = $seededTeam;
  106. //Update db with the new stage
  107. $sql_data = array();
  108. $sql_data[] = array(
  109. 'stage' => $id + 1,
  110. );
  111. $where = 'team_id = ' . $seededTeam['team_id'] . '';
  112. if(!$db->update('fifa_teams', $sql_data, $where))
  113. {
  114. echo $db->error();
  115. exit();
  116. }
  117. }
  118. }
  119. header('Location: ./index.php');
  120. }
  121. else
  122. {
  123. foreach($teams as $team)
  124. {
  125. if($team['qualified'] == 0)
  126. {
  127. $seededTeams[$team['stage']][$team['team_id']] = $team;
  128. }
  129. }
  130. }
  131. //Fetch all qualified teams, ordered
  132. foreach($teams as $team)
  133. {
  134. if($team['qualified'] > 0)
  135. {
  136. $qualifiedTeams[$team['stage']][$team['team_id']] = $team;
  137. }
  138. }
  139. //Get groups
  140. foreach($teams as $team)
  141. {
  142. $stageGroups[$team['stage']][$team['groupNo']][] = $team;
  143. }
  144. //Draw teams from given stage
  145. if(isset($_GET['draw']) && !empty($stageGroups[$_GET['draw']]) && $logged_in)
  146. {
  147. $drawStage = (int) $_GET['draw'];
  148. //Reset matches
  149. $sql = "DELETE FROM fifa_matches
  150. WHERE stage = " . $drawStage;
  151. $db->query($sql);
  152. $totalDrawTeams = count($seededTeams[$drawStage]) + count($qualifiedTeams[$drawStage]);
  153. //Determine the number of groups
  154. if($drawStage == $numStages)
  155. {
  156. //Final stage
  157. $numGroups = $totalDrawTeams / $finalTeamsPerGroup;
  158. $tPerGroup = $finalTeamsPerGroup;
  159. }
  160. elseif($drawStage == $numStages - 1)
  161. {
  162. //Penultimate stage
  163. $numGroups = $totalDrawTeams / $qualTeamsPerGroup;
  164. $tPerGroup = $qualTeamsPerGroup;
  165. }
  166. else
  167. {
  168. //All other stages
  169. $numGroups = $totalDrawTeams / 2;
  170. $tPerGroup = 2;
  171. }
  172. $stageGroups = array();
  173. $stageGroups[$drawStage] = draw_to_groups($seededTeams[$drawStage], $qualifiedTeams[$drawStage], $numGroups, $tPerGroup);
  174. //Insert groups into database
  175. foreach($stageGroups[$drawStage] as $id => $group)
  176. {
  177. $tmpGroup = $group;
  178. foreach($group as $teamId => $team)
  179. {
  180. //Update db with the new stage
  181. $sql_data = array();
  182. $sql_data[] = array(
  183. 'groupNo' => $id,
  184. );
  185. $where = 'team_id = ' . $team['team_id'];
  186. if(!$db->update('fifa_teams', $sql_data, $where))
  187. {
  188. echo $db->error();
  189. exit();
  190. }
  191. //Create matches
  192. unset($tmpGroup[$teamId]);
  193. $sql_data = array();
  194. foreach($tmpGroup as $team2)
  195. {
  196. $sql_data = array();
  197. $randTeam = array($team2, $team);
  198. shuffle($randTeam);
  199. $sql_data[] = array(
  200. 'home_team' => $randTeam[0]['team_id'],
  201. 'away_team' => $randTeam[1]['team_id'],
  202. 'group_id' => $id,
  203. 'stage' => $drawStage,
  204. );
  205. $sql_data[] = array(
  206. 'home_team' => $randTeam[1]['team_id'],
  207. 'away_team' => $randTeam[0]['team_id'],
  208. 'group_id' => $id,
  209. 'stage' => $drawStage,
  210. );
  211. if(!$db->insert('fifa_matches', $sql_data))
  212. {
  213. echo $db->error();
  214. exit();
  215. }
  216. }
  217. }
  218. }
  219. header('Location: ./index.php');
  220. }
  221. //Qualify team from given stage
  222. if(isset($_GET['qualify']) && $logged_in)
  223. {
  224. $team_id = (int) $_GET['qualify'];
  225. $sql_data[] = array(
  226. 'qualified' => 'qualified + 1',
  227. 'stage' => 'stage + 1'
  228. );
  229. $where = 'team_id = ' . $team_id;
  230. $sql = 'UPDATE fifa_teams SET qualified = qualified + 1, stage = stage + 1 WHERE team_id = '.$team_id;
  231. if(!$db->query($sql))
  232. {
  233. echo $db->error();
  234. exit();
  235. }
  236. header('Location: ./index.php');
  237. }
  238. //Qualify team from given stage
  239. if(isset($_GET['set']) && $logged_in)
  240. {
  241. $match_id = $_GET['set'];
  242. $result = $_GET['result'];
  243. $sql_data[] = array(
  244. 'result' => $result,
  245. );
  246. if(!$db->update('fifa_matches', $sql_data, 'match_id='.$match_id))
  247. {
  248. echo $db->error();
  249. exit();
  250. }
  251. header('Location: ./index.php');
  252. }
  253. function get_team_name($team_id)
  254. {
  255. global $db;
  256. $row = $db->fields('fifa_teams', array('team_name'), 'team_id = ' . $team_id);
  257. return $row['team_name'];
  258. }
  259. function draw_to_groups($seededTeams, $qualifiedTeams, $numGroups, $tPerGroup)
  260. {
  261. $groups = array();
  262. //Combine the two arrays
  263. $teamPool = $seededTeams;
  264. foreach($qualifiedTeams as $id => $team)
  265. {
  266. $teamPool[$id] = $team;
  267. }
  268. aasort($teamPool, 'team_rating');
  269. $totalTeams = count($teamPool);
  270. //Create seed pots
  271. $pots = array();
  272. $i = 1;
  273. $k = 1;
  274. $potSize = $totalTeams / $tPerGroup;
  275. foreach($teamPool as $team)
  276. {
  277. if($k > $potSize)
  278. {
  279. $i++;
  280. $k = 1;
  281. }
  282. $pots[$i][] = $team;
  283. $k++;
  284. }
  285. //Prepare groups
  286. for($i=1; $i <= $numGroups; $i++)
  287. {
  288. $groups[$i] = array();
  289. }
  290. //Draw teams
  291. $pots = array_reverse($pots, true);
  292. foreach($pots as $pot)
  293. {
  294. shuffle($pot);
  295. $g = 1;
  296. $round = 0;
  297. foreach($pot as $team)
  298. {
  299. $picked = false;
  300. while(!$picked)
  301. {
  302. if($g > $numGroups)
  303. {
  304. $g = 1;
  305. $round ++;
  306. }
  307. if(count($groups[$g]) < $tPerGroup)
  308. {
  309. if(!in_group($team['team_country'],$groups[$g],'team_country') || $round > 2000)
  310. {
  311. $groups[$g][] = $team;
  312. $picked = true;
  313. }
  314. }
  315. $g++;
  316. }
  317. }
  318. }
  319. return $groups;
  320. }
  321. //Find if the same key is in the array of arrays
  322. function in_group($value, $array, $key)
  323. {
  324. foreach($array as $team)
  325. {
  326. if($team[$key] == $value)
  327. {
  328. return true;
  329. }
  330. }
  331. return false;
  332. }
  333. //Calculate competition structure based on seed
  334. function knockoutStructure($totalTeams, $finalTeams, $seedStart, $seedInterval, $seedEnd, $reverse = true)
  335. {
  336. $debug = false;
  337. $processing = true;
  338. //Prepare local processing variables
  339. $tTeams = $totalTeams;
  340. $nTeams = $finalTeams;
  341. //Knockout stages
  342. $i = 0;
  343. $stages = array();
  344. while($processing)
  345. {
  346. //Create an array for each stage
  347. $stages[$i] = array();
  348. //Set amount to eliminate
  349. $eliminate = 0;
  350. //The seed for this stage
  351. $seed = $seedStart - $i*$seedInterval;
  352. //Make sure the seed doesn't go below the seed threshold
  353. if($seed < $seedEnd)
  354. {
  355. $seed = $seedEnd;
  356. }
  357. //Amount of seeded teams are calculated from needed teams
  358. $seededTeams = floor($seed * $nTeams);
  359. //Amount of teams needed to qualify is equal to the remaining teams
  360. $qTeams = $nTeams - $seededTeams;
  361. //Remaining total teams are reduced
  362. $tTeams -= $seededTeams;
  363. //If there are enough teams to be halved, proceed to the next stage
  364. if($tTeams > 2* $qTeams)
  365. {
  366. $stages[$i]['seeded'] = $seededTeams;
  367. $stages[$i]['qualify'] = $qTeams;
  368. }
  369. else
  370. {
  371. //Calculate the last stage(s)
  372. //Put the seeded teams back in the total teams
  373. $tTeams += $seededTeams;
  374. //The number of teams to be eliminated
  375. $eliminate = $tTeams - $nTeams;
  376. //Set the seeded and qualified teams for this stage
  377. $stages[$i]['seeded'] = $tTeams - 2*$eliminate;
  378. $stages[$i]['qualify'] = $eliminate;
  379. //If more than 0 teams need eliminated, create one previous stage
  380. if($eliminate > 0)
  381. {
  382. $stages[$i+1]['seeded'] = 2*$eliminate;
  383. $stages[$i+1]['qualify'] = 0;
  384. }
  385. //End processing
  386. $processing = false;
  387. }
  388. //Set needed teams for the previous round
  389. $nTeams = 2*$qTeams;
  390. if($debug)
  391. {
  392. print_r($stages[$i]);
  393. echo "<br>";
  394. if($tTeams > 2* $qTeams)
  395. {
  396. echo "Seed:" . $seed . "<br>";
  397. echo "seededTeams:" . $seededTeams . "<br>";
  398. echo "qTeams:" . $qTeams . "<br>";
  399. }
  400. echo "tTeams:" . $tTeams . "<br>";
  401. echo "nTeams:" . $nTeams . "<br>";
  402. echo "eliminate:" . $eliminate . "<br>";
  403. echo "<br><br>";
  404. }
  405. $i++;
  406. }
  407. if($debug && isset($stages[$i]))
  408. {
  409. print_r($stages[$i]);
  410. echo "<br>";
  411. echo "tTeams:" . $tTeams . "<br>";
  412. echo "nTeams:" . $nTeams . "<br>";
  413. echo "eliminate:" . $eliminate . "<br>";
  414. echo "<br><br>";
  415. }
  416. if($reverse)
  417. {
  418. return array_reverse($stages);
  419. }
  420. else
  421. {
  422. return $stages;
  423. }
  424. }
  425. function aasort ($array, $key) {
  426. $sorter=array();
  427. $ret=array();
  428. reset($array);
  429. foreach ($array as $ii => $va) {
  430. $sorter[$ii]=$va[$key];
  431. }
  432. arsort($sorter);
  433. foreach ($sorter as $ii => $va) {
  434. $ret[$ii]=$array[$ii];
  435. }
  436. return $ret;
  437. }
  438. ?>