/website/game_list.php

https://github.com/spacebat/aichallenge · PHP · 332 lines · 274 code · 25 blank · 33 comment · 66 complexity · 3b0b7d646d42a2fb242f08bc8c5e22f5 MD5 · raw file

  1. <?php
  2. require_once('mysql_login.php');
  3. require_once('memcache.php');
  4. require_once('pagination.php');
  5. require_once('nice.php');
  6. //require_once('api_functions.php');
  7. //require_once('session.php');
  8. // session is needed to highlight the current user
  9. // but is not included here so that json requests go faster
  10. // you must include it in your php if you wish to render html tables
  11. // used for looking at latest results only with view more link
  12. // should be smaller than page size
  13. $top_results_size = 10;
  14. // used for looking at pages with pagination links
  15. $page_size = 50;
  16. // this function doesn't really belong here, but I can't think of a good place
  17. // it works like filter_input with an optional filter and default value
  18. function get_type_or_else($key, $type=NULL, $default=NULL) {
  19. if (isset($_GET[$key])) {
  20. $value = $_GET[$key];
  21. if ($type == NULL) {
  22. return $value;
  23. } else {
  24. $filter_value = filter_var($value, $type, FILTER_NULL_ON_FAILURE);
  25. if ($filter_value !== NULL) {
  26. return $filter_value;
  27. }
  28. }
  29. }
  30. return $default;
  31. }
  32. function cache_key($page=0, $user_id=NULL, $submission_id=NULL, $map_id=NULL, $format='json') {
  33. if ($page == -1) {
  34. $page = "page_count";
  35. }
  36. if ($user_id !== NULL) {
  37. $key = "game_list:user:" . strval($user_id);
  38. } elseif ($submission_id !== NULL) {
  39. $key = "game_list:submission:" . strval($submission_id);
  40. } elseif ($map_id !== NULL) {
  41. $key = "game_list:map:" . strval($map_id);
  42. } else {
  43. $key = "game_list:all::";
  44. }
  45. return $key. ":" . strval($page) . ":" . $format;
  46. }
  47. // page 0 is all results, page 1 is the top N results
  48. function produce_cache_results($page=0, $user_id=NULL, $submission_id=NULL, $map_id=NULL) {
  49. global $memcache;
  50. global $page_size;
  51. $page_count_query = "select_game_list_page_count";
  52. $list_query = "select_game_list";
  53. if ($user_id !== NULL) {
  54. $list_select_field = "user_id";
  55. $list_id = $user_id;
  56. $list_type = "user";
  57. $list_id_field = "username";
  58. } elseif ($submission_id !== NULL) {
  59. $list_select_field = "submission_id";
  60. $list_id = $submission_id;
  61. $list_type = "submission";
  62. $list_id_field = "submission_id";
  63. } elseif ($map_id !== NULL) {
  64. $page_count_query = "select_map_game_list_page_count";
  65. $list_query = "select_map_game_list";
  66. $list_select_field = "map_id";
  67. $list_id = $map_id;
  68. $list_type = "map";
  69. $list_id_field = "map_id";
  70. } else {
  71. // make the where clause always return true
  72. $page_count_query = "select_map_game_list_page_count";
  73. $list_query = "select_map_game_list";
  74. $list_select_field = "1";
  75. $list_id = 1;
  76. $list_type = NULL;
  77. }
  78. $list_results = contest_query($page_count_query, $list_select_field, $list_id);
  79. if ($list_results) {
  80. while ($list_row = mysql_fetch_array($list_results, MYSQL_NUM)) {
  81. $row_count = $list_row[0];
  82. $page_count = ceil($row_count / $page_size);
  83. }
  84. }
  85. $memcache->set(cache_key(-1, $user_id, $submission_id, $map_id), $page_count);
  86. if ($page == 0) {
  87. $offset = 0;
  88. $limit = $row_count;
  89. } else {
  90. $offset = ($page - 1) * $page_size;
  91. $limit = $page_size;
  92. }
  93. $json = array("fields" => array(),
  94. "values" => array());
  95. if ($page > 0) {
  96. $json["page"] = $page;
  97. $json["page_count"] = $page_count;
  98. }
  99. $list_results = contest_query($list_query, $list_select_field, $list_id, $limit, $offset);
  100. $list_id_name = NULL;
  101. if ($list_results) {
  102. $field_count = mysql_num_fields($list_results);
  103. $row_count = mysql_num_rows($list_results);
  104. $field_names = array();
  105. for ($i = 0; $i < $field_count; $i++) {
  106. $field_names[] = mysql_field_name($list_results, $i);
  107. }
  108. $json["fields"] = $field_names;
  109. // this list and offset should match the results of the sql queries
  110. // select_game_list
  111. $user_fields = array("user_id", "submission_id", "username", "version", "player_id", "game_rank", "status", "skill", "mu", "sigma", "skill_change", "mu_change", "sigma_change");
  112. $user_fields_offset = 9;
  113. /*
  114. if ($user_id !== NULL or $submission_id !== NULL) {
  115. foreach ($user_fields as $user_field) {
  116. $json["fields"][] = $user_field;
  117. }
  118. }
  119. */
  120. $row_num = 0;
  121. $game_row_num = 0;
  122. $page_num = 0;
  123. $last_game_id = -1;
  124. $cur_row = NULL;
  125. while ($list_row = mysql_fetch_array($list_results, MYSQL_NUM)) {
  126. // get list name, run once
  127. if ($list_type and !$list_id_name) {
  128. $list_row_by_name = array_combine($field_names, $list_row);
  129. $list_id_name = $list_row_by_name[$list_id_field];
  130. }
  131. // get additional opponent info
  132. if ($list_row[0] == $last_game_id) {
  133. for ($i = 0; $i < count($user_fields); $i++) {
  134. $cur_row[$i + $user_fields_offset][] = $list_row[$i + $user_fields_offset];
  135. }
  136. } else {
  137. // get new game info
  138. // dump results of row
  139. if ($cur_row !== NULL) {
  140. $json["values"][] = $cur_row;
  141. $game_row_num++;
  142. }
  143. // setup new row
  144. $row_num++;
  145. $cur_row = $list_row;
  146. for ($i = 0; $i < count($user_fields); $i++) {
  147. $cur_row[$i + $user_fields_offset] = array($cur_row[$i + $user_fields_offset]);
  148. }
  149. }
  150. $last_game_id = $list_row[0];
  151. }
  152. // dump last row
  153. if ($cur_row !== NULL) {
  154. $json["values"][] = $cur_row;
  155. }
  156. // dump results
  157. if ($list_type) {
  158. $json["type"] = $list_type;
  159. $json["type_id"] = $list_id;
  160. $json["type_name"] = $list_id_name;
  161. } else {
  162. $json["type"] = "all";
  163. }
  164. $json_result = json_encode($json);
  165. $memcache->set(cache_key($page, $user_id, $submission_id, $map_id),
  166. $json_result);
  167. return $json_result;
  168. }
  169. return NULL;
  170. }
  171. function create_game_list_table($json, $top=FALSE, $targetpage=NULL) {
  172. global $top_results_size;
  173. if ($targetpage === NULL) {
  174. $targetpage = $_SERVER['PHP_SELF'];
  175. }
  176. if ($json == NULL) {
  177. return '<h4>There are no games at this time. Please check back later.</h4>';
  178. }
  179. if ($json['type'] == 'user') {
  180. $user_id = $json['type_id'];
  181. } else {
  182. $user_id = NULL;
  183. }
  184. $table = '<table class="games">';
  185. if (array_key_exists('type', $json) && strcmp($json['type'], "all") != 0) {
  186. // language by name, others by id
  187. if ($json['type'] == 'language') {
  188. $page_string = '?'.$json['type'].'='.$json['type_name'].'&page=';
  189. } else {
  190. $page_string = '?'.$json['type'].'='.$json['type_id'].'&page=';
  191. }
  192. } else {
  193. $page_string = '?page=';
  194. }
  195. if (!$top) {
  196. $table .= '<caption>'.getPaginationString($json['page'], $json['page_count'], 10, $page_string)."</caption>";
  197. }
  198. // produce header
  199. $table .= '<thead><tr><th>Time</th>';
  200. if ($user_id) {
  201. $table .= '<th>Version</th><th>Skill</th>';
  202. }
  203. $table .= '<th>Opponents</th>';
  204. if ($user_id) {
  205. $table .= '<th>Outcome</th>';
  206. $table .= '<th>Status</th>';
  207. }
  208. $table .= '<th>Map</th><th>Viewer</th></tr></thead>';
  209. if (count($json["values"]) > 0) {
  210. $table .= '<tbody>';
  211. $oddity = 'even';
  212. $fields = $json["fields"];
  213. $row_num = 0;
  214. foreach ($json["values"] as $values) {
  215. $row_num++;
  216. $row = array_combine($fields, $values);
  217. // find current user info
  218. if ($user_id) {
  219. for ($i = 0; $i < $row['players']; $i++) {
  220. if ($row["user_id"][$i] == $user_id) {
  221. $user_version = $row["version"][$i];
  222. $user_submission_id = $row["submission_id"][$i];
  223. $user_skill = $row["skill"][$i];
  224. $user_mu = $row["mu"][$i];
  225. $user_sigma = $row["sigma"][$i];
  226. $user_skill_change = $row["skill_change"][$i];
  227. $user_mu_change = $row["mu_change"][$i];
  228. $user_sigma_change = $row["sigma_change"][$i];
  229. $user_rank = $row["game_rank"][$i];
  230. $user_status = $row["status"][$i];
  231. break;
  232. }
  233. }
  234. }
  235. $oddity = $oddity == 'odd' ? 'even' : 'odd'; // quite odd?
  236. $user_class = current_username() == $row["username"] ? ' user' : '';
  237. $table .= "<tr class=\"$oddity$user_class\">";
  238. $time = new DateTime($row["timestamp"]);
  239. // $time = "<span title=\"".no_wrap(nice_interval($now->diff($time))." ago")."\">".no_wrap($time->format('j M G:i'))."</span>";
  240. $time = nice_datetime_span($time);
  241. $table .= "<td>$time</td>";
  242. if ($user_id) {
  243. $table .= "<td class=\"number\">".nice_version($user_version, NULL, $user_submission_id)."</td>";
  244. $table .= "<td class=\"number\">".nice_skill($user_skill, $user_mu, $user_sigma, $user_skill_change, $user_mu_change, $user_sigma_change)."</td>";
  245. }
  246. // TODO: consider linking the submission id instead
  247. $opponents = "";
  248. for ($i = 0; $i < $row['players']; $i++) {
  249. $opponents .= nice_opponent($row["user_id"][$i], $row["username"][$i], $row["game_rank"][$i] + 1, $row["user_id"][$i] == $user_id);
  250. }
  251. $table .= "<td class=\"list\">$opponents</td>";
  252. if ($user_id) {
  253. $outcome = nice_outcome($user_rank+1, $row['players']);
  254. $table .= "<td>$outcome</td>";
  255. $table .= "<td>$user_status</td>";
  256. }
  257. $map = nice_map($row['map_name']);
  258. $table .= "<td>$map</td>";
  259. $game = nice_game($row['game_id'], $row['game_length'], $row['winning_turn'], $row['ranking_turn'], $row['cutoff'], $user_id);
  260. $table .= "<td>$game</td>";
  261. $table .= "</tr>";
  262. if ($top and $row_num == $top_results_size) {
  263. break;
  264. }
  265. }
  266. $table .= '</tbody>';
  267. }
  268. if ($top) {
  269. $table .= '<caption align="bottom"><a href="'.$targetpage.$page_string.'1">View More &raquo;</a></caption>';
  270. }
  271. $table .= '</table>';
  272. if (!$top) {
  273. $table .= '<div style="text-align:center">'.getPaginationString($json['page'], $json['page_count'], 10, $page_string)."</div>";
  274. }
  275. return $table;
  276. }
  277. function get_game_list_json($page=0, $user_id=NULL, $submission_id=NULL, $map_id=NULL) {
  278. global $memcache;
  279. $cache_key = cache_key($page, $user_id, $submission_id, $map_id);
  280. if ($memcache) {
  281. $results = $memcache->get($cache_key);
  282. }
  283. $results = NULL; // use to force data refresh when debugging
  284. if (!$results) {
  285. $results = produce_cache_results($page, $user_id, $submission_id, $map_id);
  286. }
  287. return $results;
  288. }
  289. function get_game_list_table($page=0, $user_id=NULL, $submission_id=NULL, $map_id=NULL, $top=FALSE, $targetpage=NULL) {
  290. global $memcache;
  291. $format = $top ? 'top' : 'table';
  292. $page = $top ? 1 : $page;
  293. $cache_key = cache_key($page, $user_id, $submission_id, $map_id, $format);
  294. if ($memcache) {
  295. $results = $memcache->get($cache_key);
  296. }
  297. $results = NULL; // use to force data refresh when debugging
  298. if (!$results) {
  299. $json = get_game_list_json($page, $user_id, $submission_id, $map_id);
  300. $results = create_game_list_table(json_decode($json, true), $top, $targetpage);
  301. if ($memcache) {
  302. $memcache->set($cache_key, $results);
  303. }
  304. }
  305. return $results;
  306. }
  307. ?>