You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

233 lines
7.6 KiB

  1. <?php
  2. namespace App;
  3. use Illuminate\Database\Eloquent\Model;
  4. use Log, DB;
  5. class Mission extends Model
  6. {
  7. protected $fillable = [
  8. 'hashtag',
  9. ];
  10. public function getRouteKeyName() {
  11. return 'slug';
  12. }
  13. public function tweets() {
  14. return $this->hasMany('App\Tweet');
  15. }
  16. private function unique_trimet_transit_lines(Team $team) {
  17. static $cache = [];
  18. if(array_key_exists($team->id, $cache))
  19. return $cache[$team->id];
  20. $tweets = Tweet::where('team_id', $team->id)
  21. ->where('m1_complete', 1)->whereNotNull('m1_transit_line_id')->get();
  22. $lines = [];
  23. foreach($tweets as $tweet) {
  24. if($tweet->m1_transit_line_id && !in_array($tweet->m1_transit_line_id, $lines)) {
  25. $lines[] = $tweet->m1_transit_line_id;
  26. }
  27. }
  28. $cache[$team->id] = count($lines);
  29. return count($lines);
  30. }
  31. private function unique_transit_centers(Team $team, $with_another_team=false) {
  32. static $cache = ['with'=>[], 'without'=>[]];
  33. if(array_key_exists($team->id, $cache[$with_another_team?'with':'without']))
  34. return $cache[$with_another_team?'with':'without'][$team->id];
  35. $query = Tweet::where('team_id', $team->id)->where('m2_complete', 1);
  36. if($with_another_team)
  37. $query = $query->where('m2_with_other_team', 1);
  38. $tweets = $query->get();
  39. $centers = [];
  40. foreach($tweets as $tweet) {
  41. if($tweet->m2_transit_center_id && !in_array($tweet->m2_transit_center_id, $centers)) {
  42. $centers[] = $tweet->m2_transit_center_id;
  43. }
  44. }
  45. $cache[$with_another_team?'with':'without'][$team->id] = count($centers);
  46. return count($centers);
  47. }
  48. private function unique_documents(Team $team) {
  49. static $cache = [];
  50. if(array_key_exists($team->id, $cache))
  51. return $cache[$team->id];
  52. $tweets = Tweet::where('team_id', $team->id)->whereNotNull('m7_document_id')->get();
  53. $documents = [];
  54. foreach($tweets as $tweet) {
  55. if($tweet->m7_document_id && !in_array($tweet->m7_document_id, $documents)) {
  56. $documents[] = $tweet->m7_document_id;
  57. }
  58. }
  59. $cache[$team->id] = count($documents);
  60. return count($documents);
  61. }
  62. private function num_tweets_for_mission(Team $team, $m) {
  63. static $cache = [3=>[], 4=>[], 5=>[], 6=>[]];
  64. if(array_key_exists($team->id, $cache[$m]))
  65. return $cache[$m][$team->id];
  66. $num = Tweet::where('team_id', $team->id)->where('m'.$m.'_complete', 1)->count();
  67. $cache[$m][$team->id] = $num;
  68. return $num;
  69. }
  70. public function complete(Team $team) {
  71. switch($this->id) {
  72. case 1:
  73. // 5 unique trimet transit lines
  74. return $this->unique_trimet_transit_lines($team) >= 5;
  75. case 2:
  76. // 3 unique transit centers
  77. return $this->unique_transit_centers($team) >= 3;
  78. case 3:
  79. case 4:
  80. case 5:
  81. case 6:
  82. return $this->num_tweets_for_mission($team, $this->id) >= 1;
  83. case 7:
  84. return $this->unique_documents($team) >= 3;
  85. }
  86. }
  87. public function progress(Team $team) {
  88. switch($this->id) {
  89. case 1:
  90. return [$this->unique_trimet_transit_lines($team), 5];
  91. case 2:
  92. return [$this->unique_transit_centers($team), 3];
  93. case 3:
  94. case 4:
  95. case 5:
  96. case 6:
  97. return [$this->num_tweets_for_mission($team, $this->id), 1];
  98. case 7:
  99. return [$this->unique_documents($team), 3];
  100. }
  101. return [false,false];
  102. }
  103. public function score(Team $team) {
  104. switch($this->id) {
  105. case 1:
  106. // No points unless they hit 5 trimet transit lines
  107. if($this->complete($team)) {
  108. $score = 50;
  109. // 20 bonus for each line that is not trimet
  110. $tweets = Tweet::where('team_id', $team->id)->where('m1_complete', 1)->whereNotNull('m1_non_trimet')->get();
  111. $lines = [];
  112. foreach($tweets as $tweet) {
  113. if(!in_array($tweet->m1_non_trimet, $lines)) {
  114. $lines[] = $tweet->m1_non_trimet;
  115. }
  116. }
  117. $score += count($lines) * 20;
  118. return $score;
  119. } else {
  120. return 0;
  121. }
  122. break;
  123. case 2:
  124. // No points unless they hit 3 transit centers
  125. if($this->complete($team)) {
  126. $score = 50;
  127. // If they have more than 3 unique transit centers,
  128. // then award bonus points for any beyond the third with another team
  129. $unique_transit_centers = $this->unique_transit_centers($team);
  130. if($unique_transit_centers > 3) {
  131. // Take the total number of transit centers and subtract 3
  132. $total_possible_bonus = $unique_transit_centers - 3;
  133. // Find the number of unique transit centers with another team
  134. $unique_with_another_team = $this->unique_transit_centers($team, true);
  135. // Use the smaller of the two numbers as the bonus
  136. $score += 20 * min($total_possible_bonus, $unique_with_another_team);
  137. }
  138. // Increasing bonus points for additional transit centers
  139. if($unique_transit_centers >= 4) {
  140. $score += 10;
  141. }
  142. if($unique_transit_centers >= 5) {
  143. $score += 20;
  144. }
  145. if($unique_transit_centers >= 6) {
  146. $score += 30;
  147. }
  148. if($unique_transit_centers >= 7) {
  149. $score += (50 * ($unique_transit_centers - 6));
  150. }
  151. // Double points for each transit center that no other team goes to
  152. $this_team_tcs = Tweet::where('team_id', $team->id)->where('m2_complete', 1)
  153. ->distinct()->pluck('m2_transit_center_id')->toArray();
  154. $other_visited_tcs = Tweet::where('team_id', '!=', $team->id)->where('m2_complete', 1)
  155. ->distinct()->pluck('m2_transit_center_id')->toArray();
  156. $distinct_tcs = array_diff($this_team_tcs, $other_visited_tcs);
  157. if(count($distinct_tcs) > 0) {
  158. $score *= 2;
  159. }
  160. return $score;
  161. } else {
  162. return 0;
  163. }
  164. break;
  165. case 3:
  166. case 4:
  167. case 6:
  168. if($this->complete($team)) {
  169. return 50;
  170. } else {
  171. return 0;
  172. }
  173. case 5:
  174. if($this->complete($team)) {
  175. $score = 50;
  176. // +10 if any of their photos are tipping the bus driver
  177. $num = Tweet::where('team_id', $team->id)->where('m5_complete', 1)->where('m5_tip', 1)->count();
  178. if($num > 0)
  179. $score += 10;
  180. return $score;
  181. } else {
  182. return 0;
  183. }
  184. case 7:
  185. if($this->complete($team)) {
  186. $score = 50;
  187. // +5 for each additional photo
  188. $extra_docs = $this->unique_documents($team) - 3;
  189. if($extra_docs > 0) {
  190. $score += $extra_docs * 5;
  191. }
  192. // add bonus points for certain documents
  193. $tweets = DB::table('tweets')->select('m7_document_id', 'm7_documents.points')
  194. ->where('team_id', $team->id)
  195. ->join('m7_documents', 'm7_documents.id', '=', 'tweets.m7_document_id')
  196. ->whereNotNull('m7_document_id')
  197. ->distinct()->get();
  198. foreach($tweets as $tweet) {
  199. $score += $tweet->points;
  200. }
  201. return $score;
  202. } else {
  203. return 0;
  204. }
  205. }
  206. }
  207. }