Permalink
Browse files

Change generation so that randomness is decided on the front end. The…

… back end determines all eligible Pokemon and can be cached.
  • Loading branch information...
1 parent 309aab5 commit f3e2b8b98bddc8b0ed89889ebe621e10e987beba @nerdydrew committed Dec 20, 2016
Showing with 191 additions and 156 deletions.
  1. +1 −1 .gitignore
  2. +1 −8 .htaccess
  3. +1 −1 index.php
  4. +9 −0 pokemon_list.php
  5. +150 −20 random.js
  6. +0 −14 random.php
  7. +0 −8 setup/analytics.js
  8. +14 −0 setup/config.js
  9. +0 −14 setup/config.php
  10. +15 −90 utils.php
View
@@ -1,5 +1,5 @@
/config.php
-/analytics.js
+/config.js
/error_log
.ftpquota
View
@@ -3,14 +3,6 @@ RewriteEngine on
RewriteCond %{HTTP_HOST} ^www\.randompokemon\.com [NC]
RewriteRule (.*) http://randompokemon.com/$1 [R=301,L]
-# Redirect /random/ to random.php
-RewriteRule ^random/?$ /random.php [QSA,L]
-
-# Prevent hotlinking http://www.htaccesstools.com/hotlink-protection/
-#RewriteCond %{HTTP_REFERER} !^$
-#RewriteCond %{HTTP_REFERER} !^http(s)?://(www\.)?randompokemon.com [NC]
-#RewriteRule \.(jpg|jpeg|png|gif)$ - [NC,F,L]
-
# Cache sprites and other goodies
ExpiresActive on
ExpiresByType image/png "access plus 1 year"
@@ -19,6 +11,7 @@ ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/ico "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
+ExpiresByType text/html "access plus 1 day"
# Hide the /.git/ and /setup/ directories from being accessed online.
RedirectMatch 404 /\.git
View
@@ -21,7 +21,7 @@
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#FF4A4A">
<meta name="theme-color" content="#FFFFFF">
- <script src="analytics.js"></script>
+ <script src="config.js"></script>
<script>
logToAnalytics();
</script>
View
@@ -0,0 +1,9 @@
+<?php
+// This page reads in $_GET URL parameters, validates them, determines which
+// Pokemon fulfill the parameters, and outputs the result in JSON.
+
+require_once 'config.php';
+require_once 'utils.php';
+
+$params = validate_parameters($_GET);
+echo json_encode($params->get_list());
View
@@ -10,34 +10,99 @@ function generateRandom() {
var region = document.getElementById('region').value;
var type = document.getElementById('type').value;
- var url = "random?n="+n+"&ubers="+ubers+"&nfes="+nfes+"&natures="+natures+"&sprites="+sprites+"&forms="+forms+"&region="+region+"&type="+type;
+ var url = "pokemon_list.php?n=" + n + "&ubers=" + ubers + "&nfes=" + nfes + "&natures=" + natures + "&sprites=" + sprites + "&forms=" + forms + "&region=" + region + "&type=" + type;
- if (window.XMLHttpRequest) {
- var xmlhttp = new XMLHttpRequest();
- } else {
- // code for IE6, IE5
- var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
- }
+ var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 1) {
document.getElementById("controls").className = "loading";
}
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById("controls").className = "";
- document.getElementById("results").innerHTML = htmlifyListOfPokemon(xmlhttp.responseText);
+ var randomPokemon = generateRandomPokemon(xmlhttp.responseText);
+ document.getElementById("results").innerHTML = htmlifyListOfPokemon(randomPokemon);
logToAnalytics(url);
}
};
xmlhttp.open("GET", url, true);
xmlhttp.send();
}
+function generateRandomPokemon(eligiblePokemonJson) {
+ var eligiblePokemon = JSON.parse(eligiblePokemonJson);
+ var n = document.getElementById('n').value;
+ var randomIndices = generateDistinctRandomNumbers(eligiblePokemon.length, n);
+ var forms = document.getElementById('forms').checked;
+
+ // Keep track so that only one Pokemon can be mega.
+ var canBeMega = forms;
+
+ // Generate n random Pokemon.
+ var randomPokemon = [];
+ randomIndices.forEach(function(index) {
+ var pokemon = eligiblePokemon[index];
+ if (forms && pokemon.forms) {
+ // Pick a random form. Avoid megas, if possible.
+ pokemon = getRandomForm(pokemon.forms, false);
+
+ if (pokemon.is_mega == 1) {
+ canBeMega = false;
+ }
+ }
+
+ randomPokemon.push(pokemon);
+
+ });
+
+ if (forms && canBeMega) {
+ // Choose a mega if one hasn't already been generated.
+ var potentialIndices = getPotentialMegaIndices(eligiblePokemon, randomIndices);
+ if (potentialIndices.length > 0) {
+ var chosenIndex = getRandomElement(potentialIndices);
+ var chosenPokemon = eligiblePokemon[randomIndices[chosenIndex]];
+ randomPokemon[chosenIndex] = getRandomForm(chosenPokemon.forms, true);
+ }
+ }
+
+ return randomPokemon;
+}
+
+// Returns a list of indices for the given pokemonList of Pokemon that have mega forms.
+function getPotentialMegaIndices(eligiblePokemon, randomIndices) {
+ var indices = [];
+ for (var i=0; i<randomIndices.length; i++) {
+ var forms = eligiblePokemon[randomIndices[i]].forms;
+ if (forms) {
+ forms.forEach(function(form) {
+ if (form.is_mega == 1) {
+ indices.push(i);
+ }
+ })
+ }
+ }
+ return indices;
+}
+
+// Returns a random form from the list. Either tries to get or avoids getting a mega,
+// depending on favorMegas. An example where we can't avoid a mega: if an Ampharos
+// is generated for Dragon types.
+function getRandomForm(forms, favorMegas) {
+ var preferredMegaValue = favorMegas ? 1 : 0;
+ var nonMegaForms = forms.filter(function(form) {
+ return (form.is_mega == preferredMegaValue);
+ });
+ if (nonMegaForms.length > 0) {
+ return getRandomElement(nonMegaForms);
+ } else {
+ return getRandomElement(forms);
+ }
+}
+
// Converts a JSON array of Pokémon into an HTML ordered list.
-function htmlifyListOfPokemon(generatedPokemonJson) {
- var generatedPokemon = JSON.parse(generatedPokemonJson);
+function htmlifyListOfPokemon(generatedPokemon) {
var output = '<ol>';
- for (i=0;i<generatedPokemon.length; i++) {
+ for (i=0; i<generatedPokemon.length; i++) {
output += htmlifyPokemon(generatedPokemon[i]);
}
output += '</ol>';
@@ -47,26 +112,91 @@ function htmlifyListOfPokemon(generatedPokemonJson) {
// Converts JSON for a single Pokémon into an HTML list item.
function htmlifyPokemon(pokemon) {
- var title = (pokemon.shiny) ? 'Shiny ' + pokemon.name : pokemon.name;
+ // http://bulbapedia.bulbagarden.net/wiki/Shiny_Pok%C3%A9mon#Generation_VI
+ var shiny = Math.floor(Math.random() * 65536) < 16;
+ var sprites = document.getElementById('sprites').checked;
+ var natures = document.getElementById('natures').checked;
+
+ var title = shiny ? 'Shiny ' + pokemon.name : pokemon.name;
- if (pokemon.sprite) {
- var out = '<li title="' + title + '">';
+ if (sprites) {
+ var out = '<li title="' + title + '">';
} else {
- var out = '<li class="imageless">';
+ var out = '<li class="imageless">';
}
- if (pokemon.nature) {
- out += '<span class="nature">' + pokemon.nature + "</span> ";
+ if (natures) {
+ out += '<span class="nature">' + generateNature() + "</span> ";
}
out += pokemon.name;
- if (pokemon.shiny) {
+ if (shiny) {
out += ' <span class="shiny">&#9733;</span>';
}
- if (pokemon.sprite) {
- out += '<div class="wrapper"><img src="' + pokemon.sprite + '" alt="' + title + '" title="' + title + '" /></div>';
+ if (sprites) {
+ var sprite = getSpritePath(pokemon, shiny);
+ out += '<div class="wrapper"><img src="' + sprite + '" alt="' + title + '" title="' + title + '" /></div>';
}
out += '</li>';
return out;
}
+
+function getSpritePath(pokemon, shiny) {
+ var path = shiny ? PATH_TO_SHINY_SPRITES : PATH_TO_SPRITES;
+ var name = pokemon.id;
+ if (pokemon.sprite_suffix) {
+ name = name + '-' + pokemon.sprite_suffix;
+ }
+ return path + name + SPRITE_EXTENTION;
+}
+
+function generateNature() {
+ return getRandomElement(natures_list);
+}
+
+var natures_list = ['Adamant', 'Bashful', 'Bold', 'Brave', 'Calm', 'Careful', 'Docile', 'Gentle', 'Hardy', 'Hasty', 'Impish', 'Jolly', 'Lax', 'Lonely', 'Mild', 'Modest', 'Na&iuml;ve', 'Naughty', 'Quiet', 'Quirky', 'Rash', 'Relaxed', 'Sassy', 'Serious', 'Timid'];
+
+// Generates up to n random numbers from [0, range).
+function generateDistinctRandomNumbers(range, n) {
+ if (range > 10 * n) { // 10 is an arbitrarily chosen value
+ return generateDistinctRandomNumbersLarge(range, n);
+ } else {
+ return generateDistinctRandomNumbersSmall(range, n);
+ }
+}
+
+// Generate distinct random numbers where the possible range is closer
+// to the number of elements (n) to generate.
+function generateDistinctRandomNumbersSmall(range, n) {
+ // Instantiate array of valid numbers
+ var valid_numbers = [];
+ for (var i=0; i<range; i++) {
+ valid_numbers.push(i);
+ }
+
+ var generated_numbers = [];
+ while (generated_numbers.length < n && valid_numbers.length > 0) {
+ var random_index = Math.floor(Math.random()*valid_numbers.length);
+ generated_numbers.push(valid_numbers[random_index]);
+ valid_numbers.splice(random_index, 1);
+ }
+ return generated_numbers;
+}
+
+// Generate distinct random numbers where the possible range is much
+// larger than the number of elements (n) to generate.
+function generateDistinctRandomNumbersLarge(range, n) {
+ var numbers = [];
+ while(numbers.length < n) {
+ var random = Math.floor(Math.random() * range);
+ if (numbers.indexOf(random) < 0) {
+ numbers.push(random);
+ }
+ }
+ return numbers;
+}
+
+function getRandomElement(arr) {
+ return arr[Math.floor(Math.random()*arr.length)];
+}
View
@@ -1,14 +0,0 @@
-<?php
-// This page reads in $_GET URL parameters, validates them, generates random Pokémon
-// based on the parameters, and outputs the result in JSON.
-
-require_once 'config.php';
-require_once 'utils.php';
-
-// HTTP headers to keep this page from being cached
-header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1
-header('Pragma: no-cache'); // HTTP 1.0
-header('Expires: 0'); // Proxies
-
-$params = validate_parameters($_GET);
-echo json_encode($params->generate());
View
@@ -1,8 +0,0 @@
-// This method is used for analytics. Leave its body blank otherwise.
-function logToAnalytics(url) {
- if (typeof url === "undefined") {
- // Log the current page
- } else {
- // Log the URL provided
- }
-}
View
@@ -0,0 +1,14 @@
+// This method is used for analytics. Leave its body blank otherwise.
+function logToAnalytics(url) {
+ if (typeof url === "undefined") {
+ // Log the current page
+ } else {
+ // Log the URL provided
+ }
+}
+
+// These directories should contain sprites named by PokéDex ID
+// without leading zeros (e.g. "25.gif").
+define('PATH_TO_ANIMATED_SPRITES', '/sprites/animated/');
+define('PATH_TO_SHINY_ANIMATED_SPRITES', '/sprites/animated/shiny/');
+define('ANIMATED_SPRITE_EXTENTION', '.gif');
View
@@ -3,17 +3,3 @@
define('SQL_DATABASE', '');
define('SQL_USERNAME', '');
define('SQL_PASSWORD', '');
-
-// These directories should contain sprites named by PokéDex ID
-// without leading zeros (e.g. "25.gif").
-// These directories should contain sprites named by PokéDex ID
-// without leading zeros (e.g. "25.gif").
-define('PATH_TO_ANIMATED_SPRITES', '/sprites/animated/');
-define('PATH_TO_SHINY_ANIMATED_SPRITES', '/sprites/animated/shiny/');
-define('ANIMATED_SPRITE_EXTENTION', '.gif');
-
-define('PATH_TO_REGULAR_SPRITES', '/sprites/');
-define('PATH_TO_SHINY_REGULAR_SPRITES', '/sprites/shiny/');
-define('REGULAR_SPRITE_EXTENTION', '.png');
-
-define('DEFAULT_SPRITE', '/sprites/0.png');
Oops, something went wrong.

0 comments on commit f3e2b8b

Please sign in to comment.