├── .gitignore ├── icons ├── favicon.ico ├── favicon-16x16.png ├── favicon-32x32.png ├── apple-touch-icon.png ├── android-chrome-192x192.png ├── browserconfig.xml └── safari-pinned-tab.svg ├── package.json ├── manifest.json ├── sw.js ├── css └── styles.css ├── app.js └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /icons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulirish/pidgey-grinding/HEAD/icons/favicon.ico -------------------------------------------------------------------------------- /icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulirish/pidgey-grinding/HEAD/icons/favicon-16x16.png -------------------------------------------------------------------------------- /icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulirish/pidgey-grinding/HEAD/icons/favicon-32x32.png -------------------------------------------------------------------------------- /icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulirish/pidgey-grinding/HEAD/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulirish/pidgey-grinding/HEAD/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /icons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | #da532c 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pidgeygrinding", 3 | "description": "", 4 | "version": "0.0.1", 5 | "author": "Paul Irish", 6 | "dependencies": { 7 | 8 | }, 9 | "engines": { 10 | "node": "4.1.1" 11 | }, 12 | "devDependencies": { 13 | }, 14 | "scripts": { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "short_name": "Pidgey Grinding", 4 | "name": "Pidgey Grinding", 5 | "display": "standalone", 6 | "icons": [ 7 | { 8 | "src": "./icons/android-chrome-192x192.png", 9 | "sizes": "192x192", 10 | "type": "image/png" 11 | } 12 | ], 13 | "theme_color": "#662f17", 14 | "background_color": "#662f17", 15 | "start_url": "./" 16 | } 17 | -------------------------------------------------------------------------------- /sw.js: -------------------------------------------------------------------------------- 1 | var CACHE_NAME = 'sw-ex'; 2 | var CACHE_VERSION = 4; 3 | 4 | var filesToCache = [ 5 | './', 6 | './index.html', 7 | './css/styles.css', 8 | './app.js', 9 | './icons/android-chrome-192x192.png' 10 | ]; 11 | 12 | self.oninstall = function(event) { 13 | event.waitUntil( 14 | caches.open(CACHE_NAME + '-v' + CACHE_VERSION).then(function(cache) { 15 | return cache.addAll(filesToCache); 16 | }) 17 | ); 18 | }; 19 | 20 | self.onactivate = function(event) { 21 | var currentCacheName = CACHE_NAME + '-v' + CACHE_VERSION; 22 | caches.keys().then(function(cacheNames) { 23 | return Promise.all( 24 | cacheNames.map(function(cacheName) { 25 | if (cacheName.indexOf(CACHE_NAME) == -1) { 26 | return; 27 | } 28 | 29 | if (cacheName != currentCacheName) { 30 | return caches.delete(cacheName); 31 | } 32 | }) 33 | ); 34 | }); 35 | }; 36 | 37 | self.onfetch = function(event) { 38 | var request = event.request; 39 | event.respondWith( 40 | caches.match(request).then(function(response) { 41 | if (response) { 42 | return response; 43 | } 44 | 45 | return fetch(request).then(function(response) { 46 | var responseToCache = response.clone(); 47 | caches.open(CACHE_NAME + '-v' + CACHE_VERSION).then( 48 | function(cache) { 49 | cache.put(request, responseToCache).catch(function(err) { 50 | console.warn(request.url + ': ' + err.message); 51 | }); 52 | }); 53 | return response; 54 | }); 55 | }) 56 | ); 57 | }; 58 | 59 | 60 | // Communicate via MessageChannel. 61 | self.addEventListener('message', function(event) { 62 | console.log(`Received message from main thread: ${event.data}`); 63 | event.ports[0].postMessage(`Got message! Sending direct message back - "${event.data}"`); 64 | }); 65 | 66 | // Broadcast via postMessage. 67 | function sendMessage(message) { 68 | self.clients.matchAll().then(function(clients) { 69 | clients.map(function(client) { 70 | return client.postMessage(message); 71 | }) 72 | }); 73 | } 74 | 75 | 76 | -------------------------------------------------------------------------------- /css/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: "Open Sans", sans-serif; 3 | box-sizing: border-box; 4 | } 5 | 6 | html, body { 7 | margin: 0; 8 | height: 100%; 9 | } 10 | 11 | html { 12 | background-color: hsl(11, 26%, 24%); 13 | color: hsl(20, 16%, 93%); 14 | scroll-behavior: smooth; 15 | } 16 | 17 | @media all and (min-height: 850px) { 18 | body { 19 | background-image: url(../icons/android-chrome-192x192.png); 20 | background-position: bottom right; 21 | background-repeat: no-repeat; 22 | } 23 | } 24 | 25 | 26 | a, 27 | a:visited, 28 | a:active { 29 | text-decoration: none; 30 | color: hsl(36, 100%, 50%); 31 | } 32 | 33 | .container { 34 | display: flex; 35 | flex-direction: column; 36 | max-width: 600px; 37 | padding: 20px; 38 | margin: 0 auto; 39 | justify-content: space-between; 40 | } 41 | 42 | h1 { 43 | margin: 0 0 10px; 44 | text-align: center; 45 | font-family: "bangersregular", sans-serif; 46 | font-size: 60px; 47 | text-shadow: 2px 3px 3px black; 48 | } 49 | 50 | label { 51 | font-weight: bold; 52 | } 53 | 54 | .form { 55 | display: flex; 56 | flex-direction: column; 57 | max-width: 300px; 58 | min-width: 242px; 59 | margin: 0 auto; 60 | } 61 | 62 | input[type="number"], 63 | select { 64 | margin-top: 10px; 65 | border: none; 66 | padding: 10px; 67 | font-size: 20px; 68 | border-radius: 5px; 69 | box-shadow: 0 3px 0 0 #FF8F00; 70 | color: #662f17; 71 | background-color: white; 72 | } 73 | 74 | button { 75 | background-color: #ba6831; 76 | color: white; 77 | border: none; 78 | padding: 13px; 79 | margin: 0; 80 | border-radius: 5px; 81 | box-shadow: 0 3px 0 0 #924321; 82 | font-weight: bold; 83 | } 84 | 85 | button:hover { 86 | background-color: #924321; 87 | box-shadow: 0 3px 0 0 #662f17; 88 | } 89 | 90 | button:active { 91 | background-color: #ba6831; 92 | box-shadow: 0 3px 0 0 #924321; 93 | } 94 | 95 | 96 | input[type=number]::-webkit-inner-spin-button, 97 | input[type=number]::-webkit-outer-spin-button { 98 | -webkit-appearance: none; 99 | margin: 0; 100 | } 101 | 102 | #error { 103 | color: red; 104 | text-align: center; 105 | } 106 | #output { 107 | background: hsla(11,26%,13%,1); 108 | margin: 0 -20px; 109 | padding: 0 20px; 110 | border: 1px solid #FFC107; 111 | border-width: 2px 0; 112 | /* opacity: 0.2; */ 113 | } 114 | #output b { 115 | color: #FF5722; 116 | } 117 | 118 | #footer { 119 | margin: 20px 0 0; 120 | padding: 20px; 121 | text-align: center; 122 | font-size: 80%; 123 | } 124 | 125 | #description { 126 | text-align: center; 127 | margin-top: 0; 128 | margin-bottom: 20px; 129 | } 130 | 131 | .input-wrapper { 132 | display: flex; 133 | flex-direction: row; 134 | justify-content: space-between; 135 | } 136 | 137 | .input-element { 138 | display: flex; 139 | flex-direction: column; 140 | flex: 1; 141 | max-width: 47.5%; 142 | } -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | if ('serviceWorker' in navigator) { 2 | navigator.serviceWorker.register('sw.js', { scope: './' }).then((reg) => { 3 | if (reg.installing) { 4 | console.log('Service worker installing'); 5 | } else if(reg.waiting) { 6 | console.log('Service worker installed'); 7 | } else if(reg.active) { 8 | console.log('Service worker active'); 9 | } 10 | }).catch((error) => { 11 | console.log('Registration failed with ' + error); // Registration failed 12 | }); 13 | 14 | // Communicate with the service worker using MessageChannel API. 15 | function sendMessage(message) { 16 | return new Promise((resolve, reject) => { 17 | const messageChannel = new MessageChannel(); 18 | messageChannel.port1.onmessage = function(event) { 19 | resolve(`Direct message from SW: ${event.data}`); 20 | }; 21 | 22 | navigator.serviceWorker.controller.postMessage(message, [messageChannel.port2]) 23 | }); 24 | } 25 | } 26 | 27 | 28 | // bling.js 29 | var $ = window.$ = document.querySelector.bind(document); 30 | var $$ = window.$$ = document.querySelectorAll.bind(document); 31 | Node.prototype.on = window.on = function(name, fn) { 32 | this.addEventListener(name, fn); 33 | } 34 | NodeList.prototype.__proto__ = Array.prototype; 35 | NodeList.prototype.on = NodeList.prototype.addEventListener = (function(name, fn) { 36 | this.forEach(function(elem) { 37 | elem.on(name, fn); 38 | }); 39 | }); 40 | 41 | 42 | /** 43 | * Adapted from http://www.pidgeycalc.com/ by BaiChanKheo 44 | */ 45 | 46 | var TIME_TO_EVOLVE = 30; 47 | var CANDIES_TO_EVOLVE = 12; 48 | var POKEMON_NAME = "Pidgey"; 49 | 50 | // Listener for select changes 51 | $("#pokemon").on("change", function(e) { 52 | var elem = e.currentTarget; 53 | POKEMON_NAME = elem.options[elem.selectedIndex].text; 54 | CANDIES_TO_EVOLVE = +elem.options[elem.selectedIndex].value; 55 | $("#selected-pokemon").innerHTML = POKEMON_NAME; 56 | }); 57 | 58 | $$("input").forEach(function(e){ 59 | e.on("input", calculate); 60 | }); 61 | $("select").on("change", calculate); 62 | //$('button').on('click', calculate); 63 | calculate(); 64 | 65 | // Do this when submit is clicked 66 | function calculate() { 67 | // Clear output 68 | $("#output").innerHTML = ""; 69 | 70 | // Get input amounts 71 | var pidgeys = parseInt($("#pidgey-amount").value, 10) || 0; 72 | var candies = parseInt($("#candy-amount").value, 10) || 0; 73 | 74 | if (pidgeys > 99999 || candies > 99999) { 75 | $("#error").innerHTML = "Too many " + POKEMON_NAME + "s or Candies!"; 76 | } else { 77 | $("#error").innerHTML = ""; 78 | 79 | // Counters 80 | var evolveCount = 0; 81 | var transferCount = 0; 82 | 83 | // How many can be evolved without transfers 84 | var canStillEvolve = true; 85 | while (canStillEvolve) { 86 | // Not enough candies to evolve or no Pidgeys 87 | if (Math.floor(candies / CANDIES_TO_EVOLVE) === 0 || pidgeys === 0) { 88 | canStillEvolve = false; 89 | } else { 90 | pidgeys--; // Evolve a Pidgey 91 | candies -= CANDIES_TO_EVOLVE; // Remove the candy 92 | candies++; // Gain 1 candy per evolution 93 | evolveCount++; 94 | if (pidgeys === 0) { 95 | break; 96 | } 97 | } 98 | } 99 | 100 | // Evolutions after transferring Pidgeys 101 | var shouldTransfer = true; 102 | while (shouldTransfer) { 103 | // Not enough to transfer and evolve or no Pidgeys left 104 | if ((candies + pidgeys) < (CANDIES_TO_EVOLVE + 1) || pidgeys === 0) { 105 | shouldTransfer = false; 106 | break; 107 | } 108 | 109 | // Keep transferring until enough candies 110 | while (candies < CANDIES_TO_EVOLVE) { 111 | transferCount++; 112 | pidgeys--; 113 | candies++; 114 | } 115 | 116 | // Evolve a Pidgey 117 | pidgeys--; 118 | candies -= CANDIES_TO_EVOLVE; 119 | candies++; 120 | evolveCount++; 121 | } 122 | 123 | var eggsToUse = Math.floor((evolveCount * TIME_TO_EVOLVE / 60) / 30); 124 | var xpToGain = (evolveCount * 1000).toLocaleString(); 125 | var evolveTime = (evolveCount * TIME_TO_EVOLVE / 60); 126 | 127 | // Output 128 | var html = ""; 129 | html += "

Transfer " + transferCount + " " + POKEMON_NAME + "s first."; 130 | html += "

Activate your Lucky Egg, then…" 131 | html += "

You can evolve " + evolveCount + " " + POKEMON_NAME + "s, gaining " + xpToGain + " XP."; 132 | html += "

Doing " + evolveCount + " evolutions (at ~30 sec each) takes " + evolveTime + " minutes."; 133 | html += "

Afterwards, you will have " + pidgeys + " " + POKEMON_NAME + "s and " + candies + " candies left over."; 134 | 135 | html += "

Lucky Egg Recommendation: "; 136 | 137 | if (eggsToUse > 0) { 138 | html += "Use " + eggsToUse + " Lucky Eggs

"; 139 | } else { 140 | html += "Don't use any Lucky Eggs until you've found more " + POKEMON_NAME + "s!

"; 141 | } 142 | 143 | $("#output").innerHTML = html; 144 | } 145 | } 146 | 147 | // just some bullshit to get the output visible while keyboarding. 148 | $$("input").forEach(function(e){ 149 | e.on("focus", function(){ 150 | // set up a one-off resize handler 151 | window.addEventListener('resize', { 152 | handleEvent: function(evt){ 153 | evt.currentTarget.removeEventListener(evt.type, this); 154 | scrollInputs(); 155 | } 156 | }) 157 | }); 158 | }); 159 | 160 | function scrollInputs(){ 161 | setTimeout(function(){ 162 | var topOfInputs = $('.input-element').getBoundingClientRect().top; 163 | window.scrollTo(0, window.scrollY + topOfInputs); 164 | }, 20); 165 | } -------------------------------------------------------------------------------- /icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 19 | 22 | 32 | 34 | 36 | 58 | 64 | 70 | 75 | 77 | 79 | 82 | 88 | 90 | 91 | 94 | 96 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Pidgey Grinding - Calculator for boosting your Pokemon Go XP quick 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 |

Pidgey Grinding

28 |

Max out your Lucky Egg XP gain in Pokémon Go

29 | 30 |
31 | 32 |
43 |
44 |
45 | 46 | 47 |
48 | 49 |
50 | 51 | 52 |
53 |
54 |
55 | 56 |

57 | 58 |
59 | 60 | 62 |
63 | 64 | 65 | 66 | --------------------------------------------------------------------------------