
Created 2025-09-23
/** * ============================================================================ * = Pokemon Guessing Game = * ============================================================================ * * This example is inspired by Ping Lin's **LoadJSON: Pokemon**: * * https://editor.p5js.org/pinglin/sketches/530Xltl3l * * You can select a Pokemon by the radio or change the search text to get a * Pokemon. Then ask others to guess the Pokemon by the ASCII art. */ const selected = recho.radio(0, ["pikachu", "charmander", "squirtle", "bulbasaur"]); const search = null; //➜ ⚡ Type: ELECTRIC //➜ ⚖️ Weight: 60 //➜ 📏 Height: 4 //➜ //➜ //➜ //➜ //➜ //➜ //➜ //➜ //➜ %% //➜ +-* #*+##% //➜ #--:..:=::-=# %+* //➜ #*:-::+*=-+ #*-:::-% //➜ #=:-=---:**= #-:::::::+ //➜ %----------*%=----+#% //➜ :-:----:::: #== //➜ *::-::=::-::*#=+*% //➜ #----:-=--::-- ## //➜ +--:::::------% //➜ ##+#% %#*=+# //➜ //➜ //➜ //➜ //➜ //➜ //➜ //➜ { echo(`⚡ Type: ${pokemon.types[0].type.name.toUpperCase()}`, {quote: false}); echo(`⚖️ Weight: ${pokemon.weight}`, {quote: false}); echo(`📏 Height: ${pokemon.height}`, {quote: false}); echo("", {quote: false}); img2ASCIIString(pokemon.sprites.front_default).then(echo); } /** * Originally, I wanted to create an example to visualize a Pokemon in ASCII * art. But I found it's not easy to tell under the current transformation * from pixels to characters. So I decided to make it a guessing game. * * In addition, this is also a good showcase for the following features: * * - How to use Data API in Recho * - How to draw image in Recho * - How to use inputs in Recho */ const pokemon = await getPokemon(search || selected); async function getPokemon(name) { const pokemon = await fetch(`https://pokeapi.co/api/v2/pokemon/${name}`); return pokemon.json(); } async function img2ASCIIString(url, cols = 60, rows = 25) { const asciiChars = " %#*+=-:. "; // From black to white. // Load the image. const img = await new Promise((resolve, reject) => { const image = new Image(); image.crossOrigin = "Anonymous"; image.onload = () => resolve(image); image.onerror = reject; image.src = url; }); const canvas = document.createElement("canvas"); canvas.width = img.width; canvas.height = img.height; const ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0); const imgData = ctx.getImageData(0, 0, img.width, img.height).data; const cellWidth = img.width / cols; const cellHeight = img.height / rows; let ascii = ""; for (let y = 0; y < rows; y++) { for (let x = 0; x < cols; x++) { // Compute the range of the cell. const startX = Math.floor(x * cellWidth); const startY = Math.floor(y * cellHeight); const endX = Math.floor((x + 1) * cellWidth); const endY = Math.floor((y + 1) * cellHeight); // Compute the brightness of the cell. let sum = 0; let count = 0; for (let py = startY; py < endY; py++) { for (let px = startX; px < endX; px++) { const idx = (py * img.width + px) * 4; const r = imgData[idx]; const g = imgData[idx + 1]; const b = imgData[idx + 2]; const brightness = 0.299 * r + 0.587 * g + 0.114 * b; sum += brightness; count++; } } const avg = sum / count; const charIndex = Math.floor((avg / 255) * (asciiChars.length - 1)); ascii += asciiChars[charIndex]; } ascii += "\n"; } return ascii; }