modaq
Version:
Quiz Bowl Reader using TypeScript, React, and MobX
249 lines • 10.3 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBonusWords = exports.Bonus = exports.Tossup = exports.PacketState = void 0;
const mobx_1 = require("mobx");
const mobx_sync_1 = require("mobx-sync");
const FormattedTextParser = __importStar(require("../parser/FormattedTextParser"));
require("../parser/IFormattedText");
require("./IGameFormat");
class PacketState {
constructor() {
// Anything with methods/computeds not at the top level needs to use @format to deserialize correctly
Object.defineProperty(this, "tossups", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "bonuses", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "name", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
mobx_1.makeAutoObservable(this);
this.tossups = [];
this.bonuses = [];
this.name = undefined;
}
setTossups(tossups) {
this.tossups = tossups;
}
setBonuses(bonuses) {
this.bonuses = bonuses;
}
setName(name) {
this.name = name;
}
}
__decorate([
mobx_sync_1.format((deserializedArray) => {
return deserializedArray.map((deserializedTossup) => {
return new Tossup(deserializedTossup.question, deserializedTossup.answer, deserializedTossup.metadata);
});
})
], PacketState.prototype, "tossups", void 0);
exports.PacketState = PacketState;
class Tossup {
constructor(question, answer, metadata) {
Object.defineProperty(this, "question", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "answer", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "metadata", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
mobx_1.makeAutoObservable(this);
this.question = question;
this.answer = answer;
this.metadata = metadata;
}
getPointsAtPosition(format, wordIndex, isCorrect = true) {
// If there's no powers, default to 10 points
if (format.powers.length === 0 && isCorrect) {
return 10;
}
const tossupWords = this.getWords(format);
const words = tossupWords.map((questionText) => questionText.word.reduce((result, text) => result + text.text, "").trim());
// Ignore the last word, which is an end of question marker
const lastIndex = words.length - 1;
let powerMarkerIndex = 0;
for (let i = 0; i < format.powers.length; i++) {
const powerMarker = format.powers[i].marker.trim();
const currentPowerMarkerIndex = words.findIndex((value, index) => index >= powerMarkerIndex && value.startsWith(powerMarker));
if (currentPowerMarkerIndex === -1) {
continue;
}
powerMarkerIndex = currentPowerMarkerIndex;
const powerMarkerWord = tossupWords[powerMarkerIndex];
// To get the word index, we need to subtract the count of non-words from the text index. We only have the
// non-word index, so we have to add 1 to that to get the count (TI - (NWI + 1)). If we use < rather than
// <=, we can remove the -1.
if (isCorrect &&
powerMarkerIndex !== lastIndex &&
!powerMarkerWord.canBuzzOn &&
wordIndex < powerMarkerWord.textIndex - powerMarkerWord.nonWordIndex) {
return format.powers[i].points;
}
}
if (!isCorrect) {
// If we're at the end of the question, don't count it as a neg
// We add an extra word for the end of question marker, so remove that from the list of words, as well as all of
// the power markers we skipped
const lastWord = tossupWords[tossupWords.length - 1];
if (!lastWord.canBuzzOn) {
// Something weird is happening, since the last word should always be buzzable (as the end marker).
throw new Error("Last word not buzzable, but must be buzzable by design");
}
return wordIndex >= lastWord.wordIndex ? 0 : format.negValue;
}
// Not in power, so return the default value
return 10;
}
getWords(format) {
const formattedTexts = this.formattedQuestionText(format);
const words = [];
let wordIndex = 0;
let nonwordIndex = 0;
for (let i = 0; i < formattedTexts.length; i++) {
const word = formattedTexts[i];
const fullText = word.reduce((result, text) => result + text.text, "");
const isLastWord = i === formattedTexts.length - 1;
const inPronunciationGuide = word.length > 0 && word[0].pronunciation === true;
// We need to skip over power markers and not count them when we calculate buzz points
let canBuzzOn = true;
let index = wordIndex;
const trimmedText = fullText.trim();
const powerMarkerIndex = format.powers.findIndex((power) => trimmedText.startsWith(power.marker));
if (isLastWord) {
// Last word should always be the terminal character, which can't be a power or in a pronunciation guide
wordIndex++;
}
else if (powerMarkerIndex >= 0) {
// Power markers have priority over pronunciation guides, and shouldn't be treated as such
for (const segment of word) {
segment.pronunciation = false;
}
canBuzzOn = false;
index = nonwordIndex;
nonwordIndex++;
}
else if (inPronunciationGuide) {
canBuzzOn = false;
index = nonwordIndex;
nonwordIndex++;
}
else {
wordIndex++;
}
if (canBuzzOn) {
words.push({
wordIndex: index,
textIndex: i,
word,
isLastWord,
canBuzzOn,
});
}
else {
words.push({
nonWordIndex: index,
textIndex: i,
word,
canBuzzOn,
});
}
}
return words;
}
formattedQuestionText(format) {
// Include the ■ to give an end of question marker
return FormattedTextParser.splitFormattedTextIntoWords(this.question, {
pronunciationGuideMarkers: format.pronunciationGuideMarkers,
}).concat([[{ text: "■END■", bolded: true, emphasized: false, required: false, pronunciation: false }]]);
}
}
exports.Tossup = Tossup;
Object.defineProperty(Tossup, "noPronunciationGuides", {
enumerable: true,
configurable: true,
writable: true,
value: [undefined, undefined]
});
class Bonus {
constructor(leadin, parts, metadata) {
Object.defineProperty(this, "leadin", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "parts", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "metadata", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
// We don't use makeAutoObservable because leadin doesn't need to be observable (never changes)
mobx_1.makeAutoObservable(this);
this.leadin = leadin.trim();
this.parts = parts;
this.metadata = metadata;
}
}
exports.Bonus = Bonus;
function getBonusWords(text, format) {
return FormattedTextParser.parseFormattedText(text, {
pronunciationGuideMarkers: format.pronunciationGuideMarkers,
});
}
exports.getBonusWords = getBonusWords;
//# sourceMappingURL=PacketState.js.map