示例#1
0
 public static function generate(array $params)
 {
     $active = array_shift($params) !== 'past';
     $brackets = Lib\Cache::fetch(function () use($active) {
         $allBrackets = Api\Bracket::getAll();
         // Filter out active/completed brackets
         $brackets = [];
         foreach ($allBrackets as $bracket) {
             if ($active && ($bracket->state == BS_ELIMINATIONS || $bracket->state == BS_VOTING || $bracket->state == BS_NOMINATIONS)) {
                 $bracket->title = Api\Round::getBracketTitleForActiveRound($bracket);
                 $brackets[] = $bracket;
             }
             if (!$active && $bracket->state == BS_FINAL) {
                 $brackets[] = $bracket;
             }
         }
         // Check for card images
         foreach ($brackets as $bracket) {
             if (is_readable('./images/bracket_' . $bracket->id . '_card.jpg')) {
                 $bracket->cardImage = '/images/bracket_' . $bracket->id . '_card.jpg';
             } else {
                 $bracket->entrants = Api\Character::getRandomCharacters($bracket, 9);
             }
         }
         return $brackets;
     }, 'Controller::Brackets_displayBrackets_' . ($active ? 'active' : 'completed'));
     Lib\Display::addKey('page', 'brackets');
     $title = $active ? 'Current Brackets' : 'Past Brackets';
     Lib\Display::renderAndAddKey('content', 'bracketsView', ['brackets' => $brackets, 'title' => $title]);
 }
示例#2
0
 private static function _getCurrentRounds()
 {
     $retVal = null;
     $bracketId = Lib\Url::GetInt('bracketId', null);
     if ($bracketId) {
         $retVal = \Api\Round::getCurrentRounds($bracketId);
     }
     return $retVal;
 }
示例#3
0
 public static function generate(array $params)
 {
     $bracket = self::_getBracket(array_shift($params));
     if ($bracket) {
         $stats = Api\Round::getVotingStats($bracket->id);
         if ($stats) {
             $out = new stdClass();
             $out->bracket = $bracket;
             $out->stats = $stats;
             Lib\Display::renderAndAddKey('content', 'admin/stats', $out);
         }
     }
 }
示例#4
0
 /**
  * Generates a list of characters in a bracket (ordered by seed) and their performance
  * in said bracket
  */
 public static function getEntrantPerformanceStats(Bracket $bracket, $force = false)
 {
     return Lib\Cache::fetchLongCache(function () use($bracket) {
         // Get all tourney rounds and characters for this bracket
         $characters = Character::queryReturnAll(['bracketId' => $bracket->id, 'seed' => ['null' => false]], ['seed' => 'asc']);
         $rounds = Round::queryReturnAll(['bracketId' => $bracket->id, 'final' => 1, 'tier' => ['gt' => 0]], ['id' => 'asc']);
         // Create a hash out of the characters
         $temp = [];
         foreach ($characters as $character) {
             $temp[$character->id] = $character;
         }
         $characters = $temp;
         // Sort the rounds out based on character for faster access later
         $characterRounds = [];
         foreach ($rounds as $round) {
             // Decorate the round with full character models
             $round->character1 = $characters[$round->character1Id];
             $round->character2 = $characters[$round->character2Id];
             self::_addRoundToCharacterRounds($round, $round->character1Id, $characterRounds);
             self::_addRoundToCharacterRounds($round, $round->character2Id, $characterRounds);
         }
         $retVal = [];
         foreach ($characters as $character) {
             $roundsForCharacter = array_values($characterRounds[$character->id]);
             $closestDiff = -1;
             $closestRound = null;
             $lostTo = null;
             $totalVotes = 0;
             foreach ($roundsForCharacter as $round) {
                 // Heheheh... so gross
                 $isCharacter1 = $round->character1Id == $character->id;
                 $totalVotes += $isCharacter1 ? $round->character1Votes : $round->character2Votes;
                 $diff = abs($round->character1Votes - $round->character2Votes);
                 if ($diff < $closestDiff || $closestDiff === -1) {
                     $closestDiff = $diff;
                     // This case should be small enough that re-instantiating through a loop
                     // shouldn't prove too much of a performance concern (especially since
                     // it's generated only once per new round). Will monitor in production
                     $closestRound = (object) ['character' => $isCharacter1 ? $round->character2 : $round->character1, 'difference' => $closestDiff, 'round' => $round];
                 }
                 $lost = $isCharacter1 && $round->character1Votes < $round->character2Votes || !$isCharacter1 && $round->character2Votes < $round->character1Votes;
                 $lostTo = $lost ? (object) ['character' => $isCharacter1 ? $round->character2 : $round->character1, 'lostBy' => $diff, 'round' => $round] : null;
             }
             $retVal[] = (object) ['character' => $character, 'closestRound' => $closestRound, 'lostTo' => $lostTo, 'totalVotes' => $totalVotes, 'group' => chr(65 + $roundsForCharacter[0]->group)];
         }
         return $retVal;
     }, 'Stats::PerformanceStats_' . $bracket->id, $force);
 }
示例#5
0
 public static function _generateBracket(Api\Bracket $bracket)
 {
     $retVal = null;
     if ($bracket) {
         $availableEntrants = Api\Round::getRoundCountForTier($bracket, 0);
         // Can't have much of a bracket with only two entrants...
         if ($availableEntrants < 2) {
             $message = self::_createMessage('error', 'There are not enough entrants to generate a bracket :(');
             self::_main($message);
         } else {
             if (count($_POST) > 0) {
                 $entrants = Lib\Url::Post('entrants', true);
                 $groups = Lib\Url::Post('groups', true);
                 if ($entrants && $groups) {
                     // Verify that the entrants/groups combo doesn't exceed to number of available entrants
                     if ($entrants * $groups > $availableEntrants) {
                         $message = self::_createMessage('error', 'Cannot generate a bracket of that size');
                         self::_main($message);
                     } else {
                         $bracket->advance();
                         if ($bracket->createBracketFromEliminations($entrants * $groups, $groups)) {
                             $message = self::_createMessage('success', 'Voting for bracket "' . $bracket->name . '" has successfully started!');
                             self::_refreshCaches($bracket);
                             self::_main($message);
                         } else {
                             $message = self::_createMessage('error', 'There are not enough entrants to create a bracket of that size');
                             self::_main($message);
                         }
                     }
                 } else {
                     $message = self::_createMessage('error', 'There was an error starting the bracket');
                     self::_main($message);
                 }
             } else {
                 $out = (object) ['bracket' => $bracket, 'count' => $availableEntrants];
                 Lib\Display::renderAndAddKey('content', 'admin/start_bracket', $out);
             }
         }
     }
 }
示例#6
0
 public static function generate(array $params)
 {
     $user = self::_checkLogin();
     self::_enableAd();
     $perma = array_shift($params);
     $bracket = Api\Bracket::getBracketByPerma($perma);
     if ($bracket->start <= time() && ($bracket->state == BS_ELIMINATIONS || $bracket->state == BS_VOTING || $bracket->state == BS_WILDCARD)) {
         $cacheKey = 'CurrentRound_' . $bracket->id . '_' . $user->id;
         $out = Lib\Cache::fetch(function () use($user, $bracket) {
             $out = new stdClass();
             $out->userId = $user->id;
             $out->round = Api\Round::getCurrentRounds($bracket->id);
             $out->title = Api\Round::getBracketTitleForActiveRound($bracket);
             return $out;
         }, $cacheKey, CACHE_MEDIUM);
         if ($out) {
             $out->bracket = $bracket;
             $template = $out->bracket->state == BS_ELIMINATIONS ? 'eliminations' : 'voting';
             if ($bracket->state != BS_ELIMINATIONS) {
                 $entrantSwap = Lib\TestBucket::get('entrantSwap');
                 if ($entrantSwap !== 'control') {
                     foreach ($out->round as $round) {
                         // Interesting side effect that I had not considered before:
                         // When TestBucket initializes, it's setting the random seed for the entire RNG (duh).
                         // That means the following random line will produce a static set of results, so the
                         // user experience won't be wonky.
                         if ($entrantSwap === 'flip' || $entrantSwap === 'random' && rand() % 2 === 0) {
                             $round = self::_flipEntrants($round);
                         }
                     }
                 }
             }
             Lib\Display::addKey('page', 'vote');
             Lib\Display::addKey('title', $bracket->name . ' - Voting' . DEFAULT_TITLE_SUFFIX);
             Lib\Display::renderAndAddKey('content', $template, $out);
         }
     }
 }
示例#7
0
 private static function _vote($user)
 {
     $out = new stdClass();
     $out->success = false;
     $bracketId = Lib\Url::Post('bracketId', true);
     $bracket = Api\Bracket::getById($bracketId);
     if ($bracket) {
         $state = $bracket ? (int) $bracket->state : null;
         if ($bracket->isLocked()) {
             $out->message = 'Voting is closed for this round. Please refresh to see the latest round.';
         } else {
             if ($state === BS_ELIMINATIONS || $state === BS_VOTING) {
                 if (self::_verifyAccountAge($user, $bracket)) {
                     // Break the votes down into an array of round/character objects
                     $votes = [];
                     foreach ($_POST as $key => $val) {
                         if (strpos($key, 'round:') === 0) {
                             $key = str_replace('round:', '', $key);
                             $obj = new stdClass();
                             $obj->roundId = (int) $key;
                             $obj->characterId = (int) $val;
                             $votes[] = $obj;
                         }
                     }
                     $count = count($votes);
                     if ($count > 0) {
                         $query = 'INSERT INTO `votes` (`user_id`, `vote_date`, `round_id`, `character_id`, `bracket_id`) VALUES ';
                         $params = [':userId' => $user->id, ':date' => time(), ':bracketId' => $bracketId];
                         $insertCount = 0;
                         // Only run an insert for rounds that haven't been voted on
                         $rounds = Api\Votes::getOpenRounds($user, $votes);
                         for ($i = 0; $i < $count; $i++) {
                             if (!isset($rounds[$votes[$i]->roundId])) {
                                 $query .= '(:userId, :date, :round' . $i . ', :character' . $i . ', :bracketId),';
                                 $params[':round' . $i] = $votes[$i]->roundId;
                                 $params[':character' . $i] = $votes[$i]->characterId;
                                 $insertCount++;
                                 $rounds[$votes[$i]->roundId] = true;
                             }
                         }
                         if ($insertCount > 0) {
                             $query = substr($query, 0, strlen($query) - 1);
                             if (Lib\Db::Query($query, $params)) {
                                 $out->success = true;
                                 // I am vehemently against putting markup in the controller, but there's much refactor needed to make this right
                                 // So, that's a note that it will be changed in the future
                                 $out->message = 'Your votes were successfully submitted! <a href="/results/' . $bracket->perma . '">View Results</a>';
                                 // Oops, I did it again...
                                 if ($bracket->externalId) {
                                     $out->message .= ' or <a href="http://redd.it/' . $bracket->externalId . '" target="_blank">discuss on reddit</a>.';
                                 }
                                 // Clear any user related caches
                                 $round = Api\Round::getById($votes[0]->roundId);
                                 Lib\Cache::Set('GetBracketRounds_' . $bracketId . '_' . $round->tier . '_' . $round->group . '_' . $user->id, false);
                                 Lib\Cache::Set('GetBracketRounds_' . $bracketId . '_' . $round->tier . '_all_' . $user->id, false);
                                 Lib\Cache::Set('CurrentRound_' . $bracketId . '_' . $user->id, false);
                                 $bracket->getVotesForUser($user, true);
                             } else {
                                 $out->message = 'There was an unexpected error. Please try again in a few moments.';
                             }
                         } else {
                             $out->message = 'Voting for this round has closed';
                             $out->code = 'closed';
                         }
                     } else {
                         $out->message = 'No votes were submitted';
                     }
                 } else {
                     $out->message = 'Your reddit account is not old enough to vote in this bracket';
                 }
             } else {
                 $out->message = 'Voting is closed on this bracket';
                 $out->code = 'closed';
             }
         }
     } else {
         $out->message = 'Invalid parameters';
     }
     return $out;
 }
示例#8
0
 /**
  * Refreshes various generic caches. This is expensive; use sparingly
  */
 protected static function _refreshCaches(Api\Bracket $bracket = null)
 {
     Lib\Cache::setDisabled(true);
     // Refresh the main collections
     Api\Bracket::getAll();
     Api\Bracket::getUserOwnedBrackets(self::$_user);
     \Controller\Brackets::generate(['past']);
     \Controller\Brackets::generate([]);
     // Refresh a single bracket if specified
     if ($bracket) {
         Api\Bracket::getBracketByPerma($bracket->perma);
         Api\Round::getCurrentRounds($bracket->id);
         $bracket->getResults();
     }
     Lib\Cache::setDisabled(false);
 }
示例#9
0
 /**
  * Takes the results from the elimination rounds and creates a seeded bracket
  */
 public function createBracketFromEliminations($entrants, $groups)
 {
     $retVal = false;
     if (is_numeric($entrants)) {
         // Generate the bracket template
         $seeding = self::generateSeededBracket($entrants);
         // Get the max vote counts for each day
         $result = Lib\Db::Query('SELECT COUNT(1) AS total, r.round_group FROM votes v INNER JOIN round r ON r.round_id = v.round_id WHERE v.bracket_id = :bracketId GROUP BY r.round_group', [':bracketId' => $this->id]);
         $groupCounts = [];
         $max = 0;
         while ($row = Lib\Db::Fetch($result)) {
             $votes = (int) $row->total;
             $groupCounts[(int) $row->round_group] = $votes;
             $max = $votes > $max ? $votes : $max;
         }
         $characters = [];
         $result = Lib\Db::Query('SELECT COUNT(1) AS total, c.*, r.round_group FROM `round` r INNER JOIN `character` c ON c.character_id = r.round_character1_id LEFT OUTER JOIN votes v ON v.character_id = c.character_id WHERE r.round_tier = 0 AND r.bracket_id = :bracketId GROUP BY c.character_id', [':bracketId' => $this->id]);
         // Ensure that we have characters and there are at least enough to meet the bracket constraints
         if ($result && $result->count >= $entrants) {
             while ($row = Lib\Db::Fetch($result)) {
                 $obj = new Character($row);
                 // Normalize the votes against the highest day of voting to ensure that seeding order is reflective of flucuations in daily voting
                 // $obj->adjustedVotes = round(($obj->votes / $groups[$obj->group]) * $max);
                 $obj->adjustedVotes = round((int) $row->total / $groupCounts[(int) $row->round_group] * $max);
                 $characters[] = $obj;
             }
             // Reorder by adjusted votes
             usort($characters, function ($a, $b) {
                 return $a->adjustedVotes < $b->adjustedVotes ? 1 : -1;
             });
             // Set up the rounds
             $groupSplit = $entrants / $groups;
             for ($i = 0; $i < $entrants; $i += 2) {
                 $round = new Round();
                 $round->bracketId = $this->id;
                 $round->tier = 1;
                 $round->order = ($i + 1) % $groupSplit;
                 $round->group = floor($i / $groupSplit);
                 // Get the correct character and save their seed
                 $character1 = $characters[$seeding[$i] - 1];
                 $character1->seed = $seeding[$i];
                 $character1->sync();
                 $character2 = $characters[$seeding[$i + 1] - 1];
                 $character2->seed = $seeding[$i + 1];
                 $character2->sync();
                 $round->character1Id = $character1->id;
                 $round->character2Id = $character2->id;
                 $round->sync();
             }
             // Change the state to standard bracket voting
             $this->state = BS_VOTING;
             $retVal = $this->sync();
             // Force update the results cache
             $this->getResults(true);
         }
     }
     return $retVal;
 }
示例#10
0
 public static function generate(array $params)
 {
     Lib\Display::setLayout('landing');
     Lib\Display::addKey('rounds', Api\Round::getRandomCompletedRounds(30));
     Lib\Display::addKey('phrase', static::$_phrases[rand() % count(static::$_phrases)]);
 }