Function bodies 21 total
getCoinByTicker function · javascript · L1587-L1589 (3 LOC)_extract.js
export function getCoinByTicker(ticker: string): Coin | undefined {
return COINS.find((c) => c.ticker.toUpperCase() === ticker.toUpperCase());
}getPriceTier function · javascript · L6-L11 (6 LOC)game.js
function getPriceTier(price) {
for (let i = 0; i < PRICE_TIER_BOUNDARIES.length; i++) {
if (price < PRICE_TIER_BOUNDARIES[i]) return i;
}
return 9;
}areColorsAdjacent function · javascript · L30-L32 (3 LOC)game.js
function areColorsAdjacent(a, b) {
return COLOR_ADJACENCY[a]?.includes(b) ?? false;
}getCoinTypeFamily function · javascript · L42-L47 (6 LOC)game.js
function getCoinTypeFamily(type) {
for (const [family, types] of Object.entries(TYPE_FAMILIES)) {
if (types.includes(type)) return family;
}
return "Other";
}getTodayDateString function · javascript · L52-L54 (3 LOC)game.js
function getTodayDateString() {
return new Date().toISOString().split("T")[0];
}hashDateString function · javascript · L56-L68 (13 LOC)game.js
function hashDateString(dateStr) {
let h = 0x811c9dc5; // FNV offset basis
for (let i = 0; i < dateStr.length; i++) {
h ^= dateStr.charCodeAt(i);
h = Math.imul(h, 0x01000193); // FNV prime
}
h ^= h >>> 16;
h = Math.imul(h, 0x85ebca6b);
h ^= h >>> 13;
h = Math.imul(h, 0xc2b2ae35);
h ^= h >>> 16;
return Math.abs(h);
}ensureResolvedUpTo function · javascript · L73-L100 (28 LOC)game.js
function ensureResolvedUpTo(targetDateStr) {
const target = new Date(targetDateStr + "T00:00:00Z");
const launch = new Date("2026-03-24T00:00:00Z");
const ws = new Date(target);
ws.setUTCDate(ws.getUTCDate() - COOLDOWN_DAYS);
const start = ws > launch ? ws : launch;
const cursor = new Date(start);
while (cursor <= target) {
const ds = cursor.toISOString().split("T")[0];
if (!resolvedCache.has(ds)) {
const recent = new Set();
for (let i = 1; i <= COOLDOWN_DAYS; i++) {
const prev = new Date(cursor);
prev.setUTCDate(prev.getUTCDate() - i);
const c = resolvedCache.get(prev.toISOString().split("T")[0]);
if (c !== undefined) recent.add(c);
}
let idx = hashDateString(ds) % COINS.length;
let attempts = 0;
while (recent.has(idx) && attempts < COINS.length) {
idx = (idx + 1) % COINS.length;
attempts++;
}
resolvedCache.set(ds, idx);
}
cursor.setUTCDate(cursor.getUTCDate() Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
getDailyCoinIndex function · javascript · L102-L108 (7 LOC)game.js
function getDailyCoinIndex(dateStr) {
const date = dateStr ?? getTodayDateString();
if (!resolvedCache.has(date)) {
ensureResolvedUpTo(date);
}
return resolvedCache.get(date);
}getDailyPuzzleNumber function · javascript · L110-L116 (7 LOC)game.js
function getDailyPuzzleNumber(dateStr) {
const date = dateStr ?? getTodayDateString();
const target = new Date(date + "T00:00:00Z");
const diffMs = target.getTime() - LAUNCH_DATE.getTime();
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
return Math.max(1, diffDays + 1);
}fetchAllPrices function · javascript · L119-L140 (22 LOC)game.js
async function fetchAllPrices() {
const ids = COINS.map((c) => c.pythFeedId);
const params = new URLSearchParams();
ids.forEach((id) => params.append("ids[]", id));
params.append("parsed", "true");
const url = `https://hermes.pyth.network/v2/updates/price/latest?${params.toString()}`;
const res = await fetch(url);
if (!res.ok) throw new Error(`Hermes API error: ${res.status}`);
const data = await res.json();
const prices = {};
for (const parsed of data.parsed ?? []) {
const feedId = "0x" + parsed.id;
const coin = COINS.find((c) => c.pythFeedId === feedId);
if (!coin) continue;
const price = Number(parsed.price.price) * Math.pow(10, Number(parsed.price.expo));
prices[coin.ticker] = { price, tier: getPriceTier(price) };
}
return prices;
}compareNumericTier function · javascript · L143-L148 (6 LOC)game.js
function compareNumericTier(guessVal, secretVal) {
const diff = Math.abs(guessVal - secretVal);
const match = diff === 0 ? "green" : diff === 1 ? "yellow" : "red";
const direction = guessVal === secretVal ? "match" : guessVal < secretVal ? "up" : "down";
return { match, direction };
}compareGuess function · javascript · L150-L194 (45 LOC)game.js
function compareGuess(guess, secret, prices) {
// Type
let typeMatch;
if (guess.type === secret.type) typeMatch = "green";
else if (getCoinTypeFamily(guess.type) === getCoinTypeFamily(secret.type)) typeMatch = "yellow";
else typeMatch = "red";
// Color
let colorMatch;
if (guess.primaryColor === secret.primaryColor) colorMatch = "green";
else if (areColorsAdjacent(guess.primaryColor, secret.primaryColor)) colorMatch = "yellow";
else colorMatch = "red";
// Launch Year
const yearDiff = Math.abs(guess.launchYear - secret.launchYear);
const launchYear = yearDiff === 0 ? "green" : yearDiff === 1 ? "yellow" : "red";
const launchYearDir = guess.launchYear === secret.launchYear ? "match" : guess.launchYear < secret.launchYear ? "up" : "down";
// Ticker Length
const tickerResult = compareNumericTier(guess.tickerLength, secret.tickerLength);
// Price Range
const guessTier = prices[guess.ticker]?.tier ?? 5;
const secretTier = prices[secret.ticker]?.tier ??findCoin function · javascript · L197-L200 (4 LOC)game.js
function findCoin(input) {
const q = input.trim().toUpperCase();
return COINS.find((c) => c.ticker.toUpperCase() === q || c.name.toUpperCase() === q);
}getAllCoinNames function · javascript · L202-L204 (3 LOC)game.js
function getAllCoinNames() {
return COINS.map((c) => ({ name: c.name, value: c.ticker }));
}getPrices function · javascript · L16-L27 (12 LOC)index.js
async function getPrices() {
const now = Date.now();
if (now - lastPriceFetch > 60_000) {
try {
cachedPrices = await game.fetchAllPrices();
lastPriceFetch = now;
} catch (e) {
console.error("Price fetch failed:", e.message);
}
}
return cachedPrices;
}Open data scored by Repobility · https://repobility.com
getSession function · javascript · L29-L33 (5 LOC)index.js
function getSession(userId) {
const dateStr = game.getTodayDateString();
const key = `${userId}-${dateStr}`;
return { key, dateStr, session: sessions.get(key) };
}createSession function · javascript · L35-L47 (13 LOC)index.js
function createSession(userId) {
const dateStr = game.getTodayDateString();
const key = `${userId}-${dateStr}`;
const secretIndex = game.getDailyCoinIndex(dateStr);
const session = {
secretIndex,
guesses: [],
gameOver: false,
won: false,
};
sessions.set(key, session);
return session;
}buildGuessEmbed function · javascript · L50-L71 (22 LOC)index.js
function buildGuessEmbed(result, guessNum, secret, isReveal) {
const c = result.coin;
const lines = [
`**Type:** ${MATCH_EMOJI[result.type]} ${c.type}`,
`**Color:** ${MATCH_EMOJI[result.color]} ${c.primaryColor}`,
`**Year:** ${MATCH_EMOJI[result.launchYear]} ${c.launchYear} ${DIR_EMOJI[result.launchYearDir]}`,
`**Ticker:** ${MATCH_EMOJI[result.tickerLength]} ${c.ticker} (${c.tickerLength}) ${DIR_EMOJI[result.tickerLengthDir]}`,
`**Price:** ${MATCH_EMOJI[result.priceRange]} ${formatPrice(c.ticker)} ${DIR_EMOJI[result.priceRangeDir]}`,
`**FDV:** ${MATCH_EMOJI[result.fdvRange]} ${c.fdvBucket} ${DIR_EMOJI[result.fdvRangeDir]}`,
];
const embed = new EmbedBuilder()
.setTitle(`Guess #${guessNum}: ${c.name} (${c.ticker})`)
.setDescription(lines.join("\n"))
.setColor(result.type === "green" && result.color === "green" ? 0x2d8c56 : 0x22262e);
if (isReveal) {
embed.setFooter({ text: `The answer was: ${secret.name} (${secret.ticker})` });
}
formatPrice function · javascript · L73-L78 (6 LOC)index.js
function formatPrice(ticker) {
const p = cachedPrices[ticker];
if (!p) return "N/A";
if (p.price >= 1) return `$${p.price.toLocaleString("en-US", { maximumFractionDigits: 2 })}`;
return `$${p.price.toPrecision(4)}`;
}buildBoardEmbed function · javascript · L80-L110 (31 LOC)index.js
function buildBoardEmbed(session, puzzleNum) {
const secret = game.COINS[session.secretIndex];
const header = `📊 **Coindle #${puzzleNum}** — Guess ${session.guesses.length}/${MAX_GUESSES}`;
if (session.guesses.length === 0) {
return new EmbedBuilder()
.setTitle(`Coindle #${puzzleNum}`)
.setDescription("Use `/guess <coin>` to start guessing!\n\n6 categories: Type, Color, Year, Ticker Length, Price Range, FDV\n🟩 = correct 🟨 = close 🟥 = wrong\n⬆️ = go higher ⬇️ = go lower")
.setColor(0x5b8def);
}
const rows = session.guesses.map((r, i) => {
const squares = [r.type, r.color, r.launchYear, r.tickerLength, r.priceRange, r.fdvRange]
.map((m) => MATCH_EMOJI[m])
.join("");
return `\`${i + 1}.\` ${squares} **${r.coin.ticker}**`;
});
let footer = "";
if (session.won) {
footer = `\n\n🟢 **We Love Green Candles!** The answer was **${secret.name}**!`;
} else if (session.gameOver) {
footer = `\n\n🔻 **Dev Rugged.** The answer wasbuildShareText function · javascript · L112-L120 (9 LOC)index.js
function buildShareText(session, puzzleNum) {
const rows = session.guesses.map((r) => {
return [r.type, r.color, r.launchYear, r.tickerLength, r.priceRange, r.fdvRange]
.map((m) => MATCH_EMOJI[m])
.join("");
});
const result = session.won ? `${session.guesses.length}/${MAX_GUESSES}` : `X/${MAX_GUESSES}`;
return `Coindle #${puzzleNum} ${result}\n${rows.join("\n")}\nhttps://coindle.xyz`;
}