class ContentDescription { public name : string; public group : ContentUnit | ContentGroup; public description : Say | ((description : ContentDescription, group : ContentUnit | ContentGroup) => Say); private saidCount = 0; public constructor (name : string, group : ContentUnit | ContentGroup) { this.name = name; this.group = group; } public getScore () { return (this.group).getScore(); } public getDescription (group : ContentUnit | ContentGroup) : Say { this.saidCount++; if (typeof this.description == "function") { return this.description(this, group); } return this.description; } public setDescription (description : Say | string | ((description : ContentDescription, group : ContentUnit | ContentGroup) => Say) ) { if (!(description instanceof Say)) { this.description = new Say(description); } else { this.description = description; } return this; } public static pickDescriptions (cda : Array, target : ContentGroup | ContentUnit) : Array { let a = cda.slice(); let groups = []; for (let i = 0; i < a.length; i++) { let randomIndex = Math.floor(Math.random() * (a.length - i)) + i; let temp = a[i]; a[i] = a[randomIndex]; a[randomIndex] = temp; } // After shuffling the list, descriptions with the highest scores go at the top, and between those the ones with the lowest saidCounts go first // If multiple descriptions have the same score/saidCount, they are picked randomly due to the previous shuffling. a.sort((a : ContentDescription, b : ContentDescription) => { // Division by saidCount for now, to increase rotativity of descriptions // Reduce precision on final number to decrease the likelihood of printing the same descriptions always in the same order let precision = 5; let scoreA = Math.floor(precision * a.getScore() / (a.saidCount + 1)) / precision; let scoreB = Math.floor(precision * b.getScore() / (b.saidCount + 1)) / precision; if (scoreA != scoreB) return scoreB - scoreA; return 0; }); a.forEach(description => { groups.push(description.group); }); let matches = ( target).matchAgainst( groups); if (matches != undefined) { let result = []; matches.forEach(i => { result.push(a[i].getDescription(target)); result.push(new Say(" ")); }); return result; } else { console.warn("No description available for", target); return [new Say("Warning: No description available for the current situation. Please report so it can be corrected.")]; } } }