Skip to content

Commit

Permalink
close #160
Browse files Browse the repository at this point in the history
  • Loading branch information
geoffrey-wu committed Dec 21, 2023
1 parent aabf5ff commit 6d6d0b0
Show file tree
Hide file tree
Showing 13 changed files with 171 additions and 42 deletions.
12 changes: 12 additions & 0 deletions client/api-docs/random-bonus.html
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,18 @@ <h4 class="mt-4 md-2" id="parameters">Parameters</h4>
Whether to only return bonuses with 3 parts.
</div>
</li>
<li class="list-group-item">
<div>
<code>standardOnly</code><code class="text-muted">: boolean</code>
<code class="text-muted float-end fw-semibold">default: "false"</code>
</div>
<div>
Whether or not to only return questions from standard quizbowl formats.
Broadly, non-standard formats include anything that's not designed for use at an academic quizbowl tournament.
Think trash packets, single-packet sets, and side events.
Single-subject full-length tournaments (think DECAF and Lederberg) still count as "standard-format".
</div>
</li>
</ul>

<a href="#returns" class="text-body">
Expand Down
21 changes: 21 additions & 0 deletions client/api-docs/random-tossup.html
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,27 @@ <h4 class="mt-4 md-2" id="parameters">Parameters</h4>
The most recent year to search for.
</div>
</li>
<li class="list-group-item">
<div>
<code>powermarkOnly</code><code class="text-muted">: boolean</code>
<code class="text-muted float-end fw-semibold">default: "false"</code>
</div>
<div>
Whether or not to only return powermarked questions.
</div>
</li>
<li class="list-group-item">
<div>
<code>standardOnly</code><code class="text-muted">: boolean</code>
<code class="text-muted float-end fw-semibold">default: "false"</code>
</div>
<div>
Whether or not to only return questions from standard quizbowl formats.
Broadly, non-standard formats include anything that's not designed for use at an academic quizbowl tournament.
Think trash packets, single-packet sets, and side events.
Single-subject full-length tournaments (think DECAF and Lederberg) still count as "standard-format".
</div>
</li>
</ul>

<a href="#returns" class="text-body">
Expand Down
4 changes: 4 additions & 0 deletions client/multiplayer/room.html
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ <h1 class="me-auto text-danger">DO YOUR GRAD SCHOOL APPS</h1>
<input class="form-check-input" id="toggle-powermark-only" type="checkbox" role="switch">
<label class="form-check-label" for="toggle-powermark-only">Powermarked tossups only</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" id="toggle-standard-only" type="checkbox" role="switch">
<label class="form-check-label" for="toggle-standard-only">Standard format only</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" id="toggle-select-by-set-name" type="checkbox" role="switch">
<label class="form-check-label" for="toggle-select-by-set-name">Select by set name</label>
Expand Down
23 changes: 21 additions & 2 deletions client/multiplayer/room.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,12 @@ socket.onmessage = function (event) {
document.getElementById('set-settings').classList.add('d-none');
}
document.getElementById('toggle-powermark-only').disabled = data.selectBySetName;
document.getElementById('toggle-standard-only').disabled = data.selectBySetName;
break;

case 'toggle-standard-only':
logEvent(data.username, `${data.standardOnly ? 'enabled' : 'disabled'} standard format only`);
document.getElementById('toggle-standard-only').checked = data.standardOnly;
break;

case 'toggle-timer':
Expand Down Expand Up @@ -322,6 +328,12 @@ const socketOnConnectionAcknowledged = async (message) => {
document.getElementById('set-settings').classList.add('d-none');
}

document.getElementById('toggle-powermark-only').disabled = message.selectBySetName;
document.getElementById('toggle-standard-only').disabled = message.selectBySetName;

document.getElementById('toggle-powermark-only').checked = message.powermarkOnly;
document.getElementById('toggle-standard-only').checked = message.standardOnly;

switch (message.questionProgress) {
case 0:
document.getElementById('next').textContent = 'Start';
Expand Down Expand Up @@ -934,6 +946,12 @@ document.getElementById('toggle-lock').addEventListener('click', function () {
});


document.getElementById('toggle-powermark-only').addEventListener('click', function () {
this.blur();
socket.send(JSON.stringify({ type: 'toggle-powermark-only', powermarkOnly: this.checked }));
});


document.getElementById('toggle-rebuzz').addEventListener('click', function () {
this.blur();
socket.send(JSON.stringify({ type: 'toggle-rebuzz', rebuzz: this.checked }));
Expand All @@ -955,9 +973,10 @@ document.getElementById('toggle-select-by-set-name').addEventListener('click', f
}));
});

document.getElementById('toggle-powermark-only').addEventListener('click', function () {

document.getElementById('toggle-standard-only').addEventListener('click', function () {
this.blur();
socket.send(JSON.stringify({ type: 'toggle-powermark-only', powermarkOnly: this.checked }));
socket.send(JSON.stringify({ type: 'toggle-standard-only', standardOnly: this.checked }));
});

document.getElementById('toggle-timer').addEventListener('click', function () {
Expand Down
4 changes: 4 additions & 0 deletions client/singleplayer/bonuses.html
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ <h1 class="me-auto text-danger">DO YOUR GRAD SCHOOL APPS</h1>
<input class="form-check-input" id="toggle-three-part-bonuses" type="checkbox" role="switch" checked>
<label class="form-check-label" for="toggle-three-part-bonuses">Only use 3-part bonuses</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" id="toggle-standard-only" type="checkbox" role="switch">
<label class="form-check-label" for="toggle-standard-only">Standard formats only</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" id="toggle-select-by-set-name" type="checkbox" role="switch">
<label class="form-check-label" for="toggle-select-by-set-name">Select by set name</label>
Expand Down
61 changes: 40 additions & 21 deletions client/singleplayer/bonuses.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,29 @@ let questions = [{}];
*/
let randomQuestions = [];

// Room settings
const query = localStorage.getItem('singleplayer-bonus-query')
? JSON.parse(localStorage.getItem('singleplayer-bonus-query'))
: {
categories: [],
difficulties: [],
minYear: 2010,
maxYear: 2023,
packetNumbers: [],
setName: '',
subcategories: [],
threePartBonuses: true,
};
const defaults = {
categories: [],
difficulties: [],
minYear: 2010,
maxYear: 2023,
packetNumbers: [],
setName: '',
subcategories: [],
threePartBonuses: true,
version: '12-21-2023',
};

query.subcategories = query.subcategories.filter(subcategory => subcategory !== 'Math');
localStorage.setItem('singleplayer-tossup-query', JSON.stringify(query));
// Room settings
let query;
if (!localStorage.getItem('singleplayer-bonus-query')) {
query = defaults;
} else {
query = JSON.parse(localStorage.getItem('singleplayer-bonus-query'));
if (query.version !== '12-21-2023') {
query = defaults;
localStorage.setItem('singleplayer-bonus-query', JSON.stringify(query));
}
}

const settings = localStorage.getItem('singleplayer-bonus-settings')
? JSON.parse(localStorage.getItem('singleplayer-bonus-settings'))
Expand All @@ -47,6 +54,7 @@ if (settings.selectBySetName) {
document.getElementById('difficulty-settings').classList.add('d-none');
document.getElementById('set-settings').classList.remove('d-none');
document.getElementById('toggle-select-by-set-name').checked = true;
document.getElementById('toggle-standard-only').disabled = true;
document.getElementById('toggle-three-part-bonuses').disabled = true;
}

Expand Down Expand Up @@ -575,6 +583,7 @@ document.getElementById('start').addEventListener('click', async function () {
document.getElementById('toggle-select-by-set-name').addEventListener('click', function () {
this.blur();
settings.selectBySetName = this.checked;
document.getElementById('toggle-standard-only').disabled = this.checked;
document.getElementById('toggle-three-part-bonuses').disabled = this.checked;

if (this.checked) {
Expand All @@ -588,12 +597,6 @@ document.getElementById('toggle-select-by-set-name').addEventListener('click', f
localStorage.setItem('singleplayer-bonus-settings', JSON.stringify(settings));
});

document.getElementById('toggle-three-part-bonuses').addEventListener('click', function () {
this.blur();
query.threePartBonuses = this.checked;
loadRandomBonuses(query);
localStorage.setItem('singleplayer-bonus-query', JSON.stringify(query));
});

document.getElementById('toggle-show-history').addEventListener('click', function () {
this.blur();
Expand All @@ -609,6 +612,22 @@ document.getElementById('toggle-show-history').addEventListener('click', functio
});


document.getElementById('toggle-standard-only').addEventListener('click', function () {
this.blur();
query.standardOnly = this.checked;
loadRandomBonuses(query);
localStorage.setItem('singleplayer-bonus-query', JSON.stringify(query));
});


document.getElementById('toggle-three-part-bonuses').addEventListener('click', function () {
this.blur();
query.threePartBonuses = this.checked;
loadRandomBonuses(query);
localStorage.setItem('singleplayer-bonus-query', JSON.stringify(query));
});


document.getElementById('type-to-answer').addEventListener('click', function () {
this.blur();
settings.typeToAnswer = this.checked;
Expand Down
4 changes: 4 additions & 0 deletions client/singleplayer/tossups.html
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ <h1 class="me-auto text-danger">DO YOUR GRAD SCHOOL APPS</h1>
<input class="form-check-input" id="toggle-powermark-only" type="checkbox" role="switch">
<label class="form-check-label" for="toggle-powermark-only">Powermarked tossups only</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" id="toggle-standard-only" type="checkbox" role="switch">
<label class="form-check-label" for="toggle-standard-only">Standard formats only</label>
</div>
<div class="form-check form-switch">
<input class="form-check-input" id="toggle-select-by-set-name" type="checkbox" role="switch">
<label class="form-check-label" for="toggle-select-by-set-name">Select by set name</label>
Expand Down
56 changes: 37 additions & 19 deletions client/singleplayer/tossups.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,29 @@ const previous = {
celerity: 0,
};

const query = localStorage.getItem('singleplayer-tossup-query')
? JSON.parse(localStorage.getItem('singleplayer-tossup-query'))
: {
categories: [],
difficulties: [],
minYear: 2010,
maxYear: 2023,
packetNumbers: [],
powermarkOnly: false,
setName: '',
subcategories: [],
};
const defaults = {
categories: [],
difficulties: [],
minYear: 2010,
maxYear: 2023,
packetNumbers: [],
powermarkOnly: false,
setName: '',
standardOnly: false,
subcategories: [],
version: '12-21-2023',
};

query.subcategories = query.subcategories.filter(subcategory => subcategory !== 'Math');
localStorage.setItem('singleplayer-tossup-query', JSON.stringify(query));
let query;
if (!localStorage.getItem('singleplayer-tossup-query')) {
query = defaults;
} else {
query = JSON.parse(localStorage.getItem('singleplayer-tossup-query'));
if (query.version !== '12-21-2023') {
query = defaults;
localStorage.setItem('singleplayer-tossup-query', JSON.stringify(query));
}
}

const settings = localStorage.getItem('singleplayer-tossup-settings')
? JSON.parse(localStorage.getItem('singleplayer-tossup-settings'))
Expand Down Expand Up @@ -62,6 +70,7 @@ if (settings.selectBySetName) {
document.getElementById('set-settings').classList.remove('d-none');
document.getElementById('toggle-select-by-set-name').checked = true;
document.getElementById('toggle-powermark-only').disabled = true;
document.getElementById('toggle-standard-only').disabled = true;
}

if (!settings.showHistory) {
Expand Down Expand Up @@ -329,9 +338,9 @@ function isPace(setName) {
return setName.includes('PACE');
}

async function loadRandomTossups({ categories, difficulties, minYear, maxYear, number = 1, powermarkOnly, subcategories }) {
async function loadRandomTossups({ categories, difficulties, minYear, maxYear, number = 1, powermarkOnly, subcategories, standardOnly }) {
randomQuestions = [];
await fetch('/api/random-tossup?' + new URLSearchParams({ categories, difficulties, maxYear, minYear, number, powermarkOnly, subcategories }))
await fetch('/api/random-tossup?' + new URLSearchParams({ categories, difficulties, maxYear, minYear, number, powermarkOnly, subcategories, standardOnly }))
.then(response => response.json())
.then(response => response.tossups)
.then(questions => {
Expand All @@ -349,16 +358,16 @@ async function loadRandomTossups({ categories, difficulties, minYear, maxYear, n
* Get a random tossup.
* @returns
*/
async function getRandomTossup({ categories, difficulties, minYear, maxYear, powermarkOnly, subcategories }) {
async function getRandomTossup({ categories, difficulties, minYear, maxYear, powermarkOnly, subcategories, standardOnly }) {
if (randomQuestions.length === 0) {
await loadRandomTossups({ categories, difficulties, maxYear, minYear, number: 20, powermarkOnly, subcategories });
await loadRandomTossups({ categories, difficulties, maxYear, minYear, number: 20, powermarkOnly, subcategories, standardOnly });
}

const randomQuestion = randomQuestions.pop();

// Begin loading the next batch of questions (asynchronously)
if (randomQuestions.length === 0) {
loadRandomTossups({ categories, difficulties, maxYear, minYear, number: 20, powermarkOnly, subcategories });
loadRandomTossups({ categories, difficulties, maxYear, minYear, number: 20, powermarkOnly, subcategories, standardOnly });
}

return randomQuestion;
Expand Down Expand Up @@ -747,6 +756,7 @@ document.getElementById('toggle-select-by-set-name').addEventListener('click', f
this.blur();
settings.selectBySetName = this.checked;
document.getElementById('toggle-powermark-only').disabled = this.checked;
document.getElementById('toggle-standard-only').disabled = this.checked;

if (this.checked) {
document.getElementById('difficulty-settings').classList.add('d-none');
Expand Down Expand Up @@ -775,6 +785,14 @@ document.getElementById('toggle-show-history').addEventListener('click', functio
});


document.getElementById('toggle-standard-only').addEventListener('click', function () {
this.blur();
query.standardOnly = this.checked;
loadRandomTossups(query);
localStorage.setItem('singleplayer-tossup-query', JSON.stringify(query));
});


document.getElementById('type-to-answer').addEventListener('click', function () {
this.blur();
settings.typeToAnswer = this.checked;
Expand Down
6 changes: 6 additions & 0 deletions database/qbreader/get-random-bonuses.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import * as types from '../../types.js';
* @param {number} [object.minYear=2010] - the minimum year to select from. Default: 2010.
* @param {number} [object.maxYear=2023] - the maximum year to select from. Default: 2023.
* @param {number} [object.bonusLength] - if not null or undefined, only return bonuses with number of parts equal to `bonusLength`.
* @param {boolean} [object.standardOnly=false]
* @returns {Promise<types.Bonus[]>}
*/
async function getRandomBonuses({
Expand All @@ -26,6 +27,7 @@ async function getRandomBonuses({
minYear = DEFAULT_MIN_YEAR,
maxYear = DEFAULT_MAX_YEAR,
bonusLength,
standardOnly = false,
} = {}) {
const aggregation = [
{ $match: { 'set.year': { $gte: minYear, $lte: maxYear } } },
Expand All @@ -51,6 +53,10 @@ async function getRandomBonuses({
aggregation[0].$match.answers = { $size: bonusLength };
}

if (standardOnly) {
aggregation[0].$match['set.standard'] = true;
}

return await bonuses.aggregate(aggregation).toArray();
}

Expand Down
6 changes: 6 additions & 0 deletions database/qbreader/get-random-tossups.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import * as types from '../../types.js';
* @param {number} [object.minYear=2010]
* @param {number} [object.maxYear=2023]
* @param {boolean} [object.powermarkOnly=false]
* @param {boolean} [object.standardOnly=false]
* @returns {Promise<types.Tossup[]>}
*/
async function getRandomTossups({
Expand All @@ -25,6 +26,7 @@ async function getRandomTossups({
minYear = DEFAULT_MIN_YEAR,
maxYear = DEFAULT_MAX_YEAR,
powermarkOnly = false,
standardOnly = false,
} = {}) {
const aggregation = [
{ $match: { 'set.year': { $gte: minYear, $lte: maxYear } } },
Expand All @@ -48,6 +50,10 @@ async function getRandomTossups({
aggregation[0].$match.question = { $regex: '\\(\\*\\)' };
}

if (standardOnly) {
aggregation[0].$match['set.standard'] = true;
}

return await tossups.aggregate(aggregation).toArray();
}

Expand Down
2 changes: 2 additions & 0 deletions routes/api/random-bonus.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ router.get('/', async (req, res) => {
req.query.maxYear = isNaN(req.query.maxYear) ? undefined : parseInt(req.query.maxYear);
req.query.number = isNaN(req.query.number) ? undefined : parseInt(req.query.number);

req.query.standardOnly = (req.query.standardOnly === 'true');

const bonuses = await getRandomBonuses(req.query);

if (bonuses.length === 0) {
Expand Down
Loading

0 comments on commit 6d6d0b0

Please sign in to comment.