Skip to content

Commit

Permalink
Use async/await
Browse files Browse the repository at this point in the history
  • Loading branch information
artnc committed Jun 1, 2024
1 parent fa9f28b commit 35027e7
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 108 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"babel-core": "6.3.21",
"babel-loader": "6.2.0",
"babel-polyfill": "6.3.14",
"babel-preset-es2015": "6.3.13",
"babel-preset-es2017": "6.24.1",
"babel-preset-react": "6.3.13",
"chai": "3.4.1",
"classnames": "2.2.1",
Expand All @@ -24,7 +24,7 @@
},
"babel": {
"presets": [
"es2015",
"es2017",
"react"
]
},
Expand Down
5 changes: 3 additions & 2 deletions src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,11 @@ export const hydrateNewQuestion = initForNewUser => (dispatch, getState) => {
track("GET_QUESTION");
return dispatch(hydrate(hydrateState, true));
};
getQuestion(bankSize, seenQuestions, question => {
(async () => {
const question = await getQuestion(bankSize, seenQuestions);
currentQuestion = question;
!waiting && dispatchHydrate();
});
})();
delay &&
window.setTimeout(() => {
if (currentQuestion) {
Expand Down
185 changes: 85 additions & 100 deletions src/util/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const normalizeString = html => {
.trim();
};

// Fisher-Yates
/** Fisher-Yates shuffle */
const shuffleString = string => {
const a = string.split("");
const n = a.length;
Expand All @@ -29,105 +29,90 @@ const shuffleString = string => {
return a.join("");
};

const LETTERS = `${"AEHINORST".repeat(3)}${"BCDFGKLMPUVWY".repeat(2)}JXQZ`;
const DIGITS = "0123456789";

export const getQuestion = (bankSize, seenQuestions, callback) => {
const retry = () =>
window.setTimeout(
() => getQuestion(bankSize, seenQuestions, callback),
125
);
const url =
"https://corsproxy.io/?" +
encodeURIComponent(
// Add timestamp to defeat corsproxy.io caching
"http://cluebase.lukelav.in/clues/random?_=" + Date.now()
);
fetch(url)
.then(response => response.json())
.then(({ data: [question] }) => {
let {
category,
clue: prompt,
id,
response: solution,
value: difficulty,
} = question;
if ([100, 300, 500].includes(difficulty)) {
// TODO: Normalize clue values based on the threshold date 2001-11-26,
// when Jeopardy doubled all clue values. jService included airdate in
// clue API repsonses, but Cluebase requires an additional API call for
// it :/ For now we just normalize only clues whose values imply that
// they must have aired before the threshold date
difficulty *= 2;
}
solution = normalizeString(solution)
.split("/")[0]
.replace(/\(.+\)/g, "")
.replace(/^an? /, "")
.replace(/\s+/g, " ")
.replace(/</g, "") // IDK why Cluebase data sometimes has trailing "<"
.trim();
prompt = normalizeString(prompt).replace(/\s+/g, " ").trim();
category = normalizeString(category);
export const getQuestion = async (bankSize, seenQuestions) => {
const url = `https://corsproxy.io/?${encodeURIComponent(
// Add timestamp to defeat corsproxy.io caching
`http://cluebase.lukelav.in/clues/random?_=${Date.now()}`
)}`;
const response = await (await fetch(url)).json();
let {
category,
clue: prompt,
id,
response: solution,
value: difficulty,
} = response.data[0];
if ([100, 300, 500].includes(difficulty)) {
// TODO: Normalize clue values based on the threshold date 2001-11-26,
// when Jeopardy doubled all clue values. jService included airdate in
// clue API repsonses, but Cluebase requires an additional API call for
// it :/ For now we just normalize only clues whose values imply that
// they must have aired before the threshold date
difficulty *= 2;
}
solution = normalizeString(solution)
.split("/")[0]
.replace(/\(.+\)/g, "")
.replace(/^an? /, "")
.replace(/\s+/g, " ")
.replace(/</g, "") // IDK why Cluebase data sometimes has trailing "<"
.trim();
prompt = normalizeString(prompt).replace(/\s+/g, " ").trim();
category = normalizeString(category);

// Check question validity
const isValid =
difficulty >= 400 &&
difficulty <= 1600 &&
difficulty !== 1000 &&
prompt.length <= 140 &&
solution.match(/\w/g).length <= bankSize &&
// Avoid multiple-choice clues because they're too easy
!prompt.toLowerCase().includes(solution.toLowerCase()) &&
!/\((cheryl|im|jimmy|jon|kelly|sarah|sofia) |(audio|video) clue|clue crew|following clip|(heard|seen) here/i.test(
prompt
) &&
!seenQuestions.includes(id);
if (!isValid) {
console.log(
"API call returned invalid data. Retry scheduled.",
question
);
retry();
return;
}
// Check question validity
const isValid =
difficulty >= 400 &&
difficulty <= 1600 &&
difficulty !== 1000 &&
prompt.length <= 140 &&
solution.match(/\w/g).length <= bankSize &&
// Avoid multiple-choice clues because they're too easy
!prompt.toLowerCase().includes(solution.toLowerCase()) &&
!/\((cheryl|im|jimmy|jon|kelly|sarah|sofia) |(audio|video) clue|clue crew|following clip|(heard|seen) here/i.test(
prompt
) &&
!seenQuestions.includes(id);
if (!isValid) {
console.log("API call returned invalid data. Retry scheduled.", response);
await new Promise(resolve => setTimeout(resolve, 125));
return await getQuestion(bankSize, seenQuestions);
}

console.log(`API call succeeded. Solution: ${solution}`);
solution = solution.toUpperCase();
const tileString = (() => {
const solutionChars = solution.match(/\w/g);
let tileString = solutionChars.join("");
const digitRatio =
(tileString.match(/\d/g) || []).length / tileString.length;
for (let i = 0; i < bankSize - solutionChars.length; ++i) {
const pool = Math.random() < digitRatio ? DIGITS : LETTERS;
tileString += pool[Math.floor(Math.random() * pool.length)];
}
return shuffleString(tileString);
})();
const RUN_DELIMITER = '@#"';
const filteredSolution = solution.replace(/[^\w]/g, "");
callback({
category,
difficulty,
filteredSolution,
guessTileIds: new Array(filteredSolution.length).fill(null),
id,
prompt,
selectedTileId: 0,
solutionRuns: solution
.trim()
.replace(/(\w+)/g, `${RUN_DELIMITER}$1${RUN_DELIMITER}`)
.split(RUN_DELIMITER)
.filter(run => run.length)
.map(run => (run.charAt(0).match(/\w/) ? run.length : run)),
solved: false,
tiles: tileString
.split("")
.map((char, id) => ({ char, id, used: false })),
tileString,
});
});
console.log(`API call succeeded. Solution: ${solution}`);
solution = solution.toUpperCase();
const tileString = (() => {
const solutionChars = solution.match(/\w/g);
let tileString = solutionChars.join("");
const digitRatio =
(tileString.match(/\d/g) || []).length / tileString.length;
for (let i = 0; i < bankSize - solutionChars.length; ++i) {
const pool =
Math.random() < digitRatio
? "0123456789"
: `${"AEHINORST".repeat(3)}${"BCDFGKLMPUVWY".repeat(2)}JXQZ`;
tileString += pool[Math.floor(Math.random() * pool.length)];
}
return shuffleString(tileString);
})();
const RUN_DELIMITER = '@#"';
const filteredSolution = solution.replace(/[^\w]/g, "");
return {
category,
difficulty,
filteredSolution,
guessTileIds: new Array(filteredSolution.length).fill(null),
id,
prompt,
selectedTileId: 0,
solutionRuns: solution
.trim()
.replace(/(\w+)/g, `${RUN_DELIMITER}$1${RUN_DELIMITER}`)
.split(RUN_DELIMITER)
.filter(run => run.length)
.map(run => (run.charAt(0).match(/\w/) ? run.length : run)),
solved: false,
tiles: tileString.split("").map((char, id) => ({ char, id, used: false })),
tileString,
};
};
8 changes: 4 additions & 4 deletions webpack.config.babel.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import cssnano from "cssnano";
import ExtractTextPlugin from "extract-text-webpack-plugin";
import webpack from "webpack";
const cssnano = require("cssnano");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const webpack = require("webpack");

const WEBPACK_DEV_PORT = 9000;

Expand All @@ -24,7 +24,7 @@ const envConfig = PROD

/* Base config */

export default {
module.exports = {
debug: !PROD,
devServer: {
contentBase: `${__dirname}/dist`,
Expand Down

0 comments on commit 35027e7

Please sign in to comment.