Skip to content

Commit

Permalink
feat(practice-test): Implement primative v2
Browse files Browse the repository at this point in the history
  • Loading branch information
CaedenPH committed Nov 12, 2023
1 parent 9569426 commit dd767f1
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 72 deletions.
14 changes: 7 additions & 7 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,14 @@ async function main() {
const route = await startPage.displayHomePage();

// TODO: Implement routing so that practice can be situated under /practice
if (route === "practice") {
await startPage.displayTestDisclaimer();
const fatigueLevel = await startPage.displaySamnPerelliChecklist();
await startPage.displayReadyDemo(10);
// if (route === "practice") {
// await startPage.displayTestDisclaimer();
// const fatigueLevel = await startPage.displaySamnPerelliChecklist();
// await startPage.displayReadyDemo(10);

const practiceTest = new PracticeCogSpeed(config, app, graphicsManager, fatigueLevel);
return await practiceTest.start();
}
// const practiceTest = new PracticeCogSpeed(config, app, graphicsManager, fatigueLevel);
// return await practiceTest.start();
// }

// Display start page
const sleepData = await startPage.start();
Expand Down
61 changes: 38 additions & 23 deletions src/routes/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,20 @@ export class CogSpeedGame {
rounds[this.currentRound].bind(this)();
}

// Flashes the answer and then continues
async revealAnswer() {
clearTimeout(this.currentRoundTimeout);

if (!this.ui || !this.ui.answerButtons) return;

await this.ui.rippleAnimation(this.ui.answerButtons[6 - this.answer]);
await new Promise((resolve) => setTimeout(resolve, 100));
await this.ui.rippleAnimation(this.ui.answerButtons[6 - this.answer]);

await new Promise((resolve) => setTimeout(resolve, 2000));
this.buttonClicked();
}

/**
* Un-prejudiced training rounds to remind the user how to perform
* the cogspeed test.
Expand Down Expand Up @@ -158,35 +172,36 @@ export class CogSpeedGame {
* Round type 1
*/
async selfPacedStartupRound() {
// 1) Set no response timeout (roughly 6000ms)
// 1) Set no response timeout (roughly 3000ms)
// Instead of the timeout stopping the test, it just reveals the answer
// And then moves onto the next round

clearTimeout(this.currentRoundTimeout);
this.currentRoundTimeout = setTimeout(this.stop.bind(this), this.config.self_paced.no_response_duration);
this.currentRoundTimeout = setTimeout(this.revealAnswer.bind(this), this.config.self_paced.no_response_duration);

// 2) Max wrong limit (roughly 5)
const selfPacedAnswers = this.previousAnswers.filter((answer) => answer.roundType === 1);
const wrongAnswers = selfPacedAnswers.filter((answer) => answer.status === "incorrect");
if (wrongAnswers.length >= this.config.self_paced.max_wrong_count) return this.stop(2);

// 3) More than (roughly 12) correct answers that are less than (roughly 3000ms)
// But not (roughly 4) correct answers in a row
const correctAnswers = selfPacedAnswers.filter(
(answer) => answer.status === "correct" && answer.timeTaken <= this.config.self_paced.max_correct_duration,
);
if (correctAnswers.length >= this.config.self_paced.total_correct_count) return this.stop(2);
// 2) If more than (roughly 20) answers have occured, then end the test
if (selfPacedAnswers.length === this.config.total_answer_count) return this.stop(4);

// 4) If (roughly 4) correct answers in a row
// 3) If (roughly 6) correct answers in a row under (roughly 2600ms)
// We move to the next round
const lastNAnswers = selfPacedAnswers.slice(-this.config.self_paced.max_right_count);
if (lastNAnswers.filter((answer) => answer.status === "correct").length === this.config.self_paced.max_right_count) {
this.currentRound = 2;
// Set machine paced timeout
this.currentTimeout =
Math.min(
lastNAnswers.map((answer) => answer.timeTaken).reduce((a, b) => a + b, 0) / 4,
this.config.machine_paced.max_start_duration,
) - this.config.machine_paced.initial_speedup_amount; // Minimim response time (roughly 100ms)
// Call next round
return this.machinePacedRound();
const lastNCorrectAnswers = selfPacedAnswers.slice(-this.config.self_paced.max_right_count).filter((answer) => answer.status === "correct");
if (lastNCorrectAnswers.length === this.config.self_paced.max_right_count) {
// Calculate average time to ensure under (roughly 2600ms)
const averageResponseTime = lastNCorrectAnswers.reduce((a, b) => a + b.timeTaken, 0) / lastNCorrectAnswers.length;

if (this.config.self_paced.right_count_art_less_than > averageResponseTime) {
this.currentRound = 2;
// Set machine paced timeout
this.currentTimeout =
Math.min(
averageResponseTime,
this.config.machine_paced.max_start_duration,
) - this.config.machine_paced.initial_speedup_amount; // Minimim response time (roughly 100ms)
// Call next round
return this.machinePacedRound();
}
}
}

Expand Down
24 changes: 13 additions & 11 deletions src/routes/start.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,14 @@ export class StartPage {
this.container.addChild(testNowContainer);

// Practice button
const practiceContainer = this.ui.createButton("Practice test", this.app.screen.width * 0.5, this.app.screen.height * 0.825,
this.app.screen.width * 0.6, this.app.screen.height * 0.15, 20)
this.container.addChild(practiceContainer);
// const practiceContainer = this.ui.createButton("Practice test", this.app.screen.width * 0.5, this.app.screen.height * 0.825,
// this.app.screen.width * 0.6, this.app.screen.height * 0.15, 20)
// this.container.addChild(practiceContainer);

// Version text
this.createText(`Version ${this.config.version}`, this.app.screen.width * 0.5, this.app.screen.height * 0.97, 11, {wordWrap: true});

const clicked = await this.waitForKeyPress(testNowContainer, [practiceContainer]);
const clicked = await this.waitForKeyPress(testNowContainer);
return clicked === testNowContainer ? "test": "practice";
}

Expand Down Expand Up @@ -309,17 +309,19 @@ private async confirmSleepData(sleepData: { [key: string]: any }): Promise<boole
* @returns {Promise<SleepData>} The test data
*/
public async start(): Promise<SleepData | false> {
if (process.env.NODE_ENV === "development") return {fatigueLevel: 1};

// Display the test disclaimer
const ready = await this.displayTestDisclaimer();
if (!ready) return false;

// Get sleep data
let sleepData;
while (true) {
sleepData = await this.displaySleepForm();
// Confirm sleep data
if (await this.confirmSleepData(sleepData)) break;
}
// let sleepData;
// while (true) {
// sleepData = await this.displaySleepForm();
// // Confirm sleep data
// if (await this.confirmSleepData(sleepData)) break;
// }

// Display the Samn Perelli checklist
// Minus from 8 because the scale is inverted
Expand All @@ -334,7 +336,7 @@ private async confirmSleepData(sleepData: { [key: string]: any }): Promise<boole

return {
fatigueLevel,
...sleepData,
// ...sleepData,
};
}
}
5 changes: 5 additions & 0 deletions src/ui/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ export class CogSpeedGraphicsHandler {
public logoTexture: Texture;
public readyDemoTextures: Texture[];

public queryNumberSprite: Sprite | null = null;
public answerButtons: Sprite[] | null = null;

constructor(public app: Application) {
this.gearWellTexture = Texture.from(gearWellTextureImage);
this.gearTexture = Texture.from(gearTextureImage);
Expand Down Expand Up @@ -367,6 +370,8 @@ export class CogSpeedGraphicsHandler {
public createInputGear(posX: number, posY: number, game: CogSpeedGame): void {
const [container, buttons] = this.createGear(posX, posY, "input");

this.answerButtons = buttons;

for (let i = 1; i <= 6; i++) {
const button = buttons[i - 1];
button.eventMode = "dynamic";
Expand Down
37 changes: 6 additions & 31 deletions tests/game.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,45 +112,20 @@ describe("Test game algorithm", () => {
expect(setTimeout).toHaveBeenCalledTimes(3);
});

it("[sp] should fail self paced mode if there are n wrong answers", async () => {
const game = selfPacedStartupGame();

// Click the wrong answer n times
for (let i = 0; i < config.self_paced.max_wrong_count; i++) {
game.buttonClicked(-1); // Wrong answer
}
expect(game.stop).toHaveBeenCalledTimes(1);
expect(game.previousAnswers.length).toEqual(config.self_paced.number_of_training_rounds + config.self_paced.max_wrong_count);
});

it("[sp] should fail self paced mode if there are n correct answers but not m correct answers in a row", async () => {
const game = selfPacedStartupGame();

// Click the right answer n times but add in a wrong answer
// Eg 12 / 3 = 4
for (let i = 0; i < 4; i++) {
game.buttonClicked(game.answer, 100); // Right answer (<3000ms delay)
game.buttonClicked(game.answer, 100); // Right answer
game.buttonClicked(game.answer, 100); // Right answer
if (i != 3) game.buttonClicked(-1, 100); // Wrong answer
for (let i = 0; i < 100; i++) {
// game.buttonClicked(game.answer, 100); // Right answer (<3000ms delay)
// game.buttonClicked(game.answer, 100); // Right answer
// game.buttonClicked(game.answer, 100); // Right answer
game.buttonClicked(-1, 100); // Wrong answer
}
expect(game.currentRound).toBe(1);
expect(game.stop).toHaveBeenCalledTimes(1);
});

it("[sp] should not exit self paced mode if the correct answers are > than n seconds", async () => {
const game = selfPacedStartupGame();

// Click the right answer n times but add in a wrong answer
// Eg 12 / 3 = 4
for (let i = 0; i < 4; i++) {
game.buttonClicked(game.answer, (i + 1) * config.self_paced.max_correct_duration + 1); // Right answer (>3000ms delay)
game.buttonClicked(game.answer, (i + 1) * config.self_paced.max_correct_duration + 3001); // Right answer
game.buttonClicked(game.answer, (i + 1) * config.self_paced.max_correct_duration + 6001); // Right answer
if (i != 3) game.buttonClicked(-1, (i + 1) * config.self_paced.max_correct_duration + 9001); // Wrong answer
}
expect(game.stop).toHaveBeenCalledTimes(0);
});

it("[sp] should exit self paced startup mode if there are n correct answers in a row", async () => {
const game = machinePacedGame();
expect(game.currentRound).toBe(2);
Expand Down

0 comments on commit dd767f1

Please sign in to comment.