From c6ea43b6bb255a1618027459cf2af42f11f1a0c8 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Jun 2024 17:23:16 +0100 Subject: [PATCH 01/10] More challenges into verifier so they can access assertRules function --- src/game/game-verifier.ts | 11 ++--------- src/game/verifier.ts | 30 +++++++++++++++--------------- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/src/game/game-verifier.ts b/src/game/game-verifier.ts index 605b805..579bdeb 100644 --- a/src/game/game-verifier.ts +++ b/src/game/game-verifier.ts @@ -4,8 +4,6 @@ import * as url from 'url'; import type { VerifyJob } from './verifier.js'; import * as game from './game.js'; -import { challenges } from '../challenges/index.js'; -import { Primitive } from '../challenges/types.js'; const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); @@ -17,15 +15,10 @@ export const verify = ( ) => { const currentGame = game.getOrError(); const verifier = child_process.fork(path.resolve(__dirname, 'verifier.ts')); - const challenge = challenges.find((ch) => ch.key === currentGame.key); - if (!challenge) { - throw new Error('Challenge not found'); - } - - const job: VerifyJob = { + const job: VerifyJob = { file, - challenge, + key: currentGame.key, }; verifier.send(job); diff --git a/src/game/verifier.ts b/src/game/verifier.ts index ebdb371..7aae577 100644 --- a/src/game/verifier.ts +++ b/src/game/verifier.ts @@ -2,19 +2,13 @@ import lodash from 'lodash'; import { readFileSync } from 'fs'; import { runInNewContext } from 'vm'; -import type { Challenge, Primitive } from '../challenges/types.js'; import { formatTypeAndValue } from './utils.js'; +import { challenges } from '../challenges/index.js'; +import { Primitive } from '../challenges/types.js'; -export interface VerifyJob< - A extends readonly Primitive[], - R extends Primitive, -> { +export interface VerifyJob { file: string; - challenge: Omit, 'example'> & { - key: string; - solution: string; - example: string; - }; + key: string; } const hasKey = ( @@ -22,8 +16,14 @@ const hasKey = ( key: K ): obj is { [P in K]: unknown } => key in obj; -process.on('message', (entry: VerifyJob) => { +process.on('message', (entry: VerifyJob) => { try { + const challenge = challenges.find((ch) => ch.key === entry.key); + + if (!challenge) { + throw new Error('Challenge not found'); + } + const script = readFileSync(entry.file, 'utf8'); const context: { play?: unknown; module: { exports: unknown } } = { module: { @@ -56,7 +56,9 @@ process.on('message', (entry: VerifyJob) => { } try { - entry.challenge.assertions.forEach((assertion) => { + challenge.assertRules?.(script); + + challenge.assertions.forEach((assertion) => { const result = play(...assertion.input); const expected = @@ -79,8 +81,6 @@ process.on('message', (entry: VerifyJob) => { ); } }); - - entry.challenge.assertRules?.(entry.challenge.solution); } catch (err) { return process.send?.({ err: @@ -99,7 +99,7 @@ process.on('message', (entry: VerifyJob) => { console.error('Verifier failed with error:', err); process.send?.({ - err: 'Your script contains an error', + err: `Your script contains an error: ${err}`, valid: false, }); } From daebb454d3ab623616a56c613216a3ddeedcb193 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Jun 2024 17:39:00 +0100 Subject: [PATCH 02/10] Improve wrong result feedback --- src/game/utils.ts | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/game/utils.ts b/src/game/utils.ts index 0b252f4..b098e02 100644 --- a/src/game/utils.ts +++ b/src/game/utils.ts @@ -34,7 +34,10 @@ export const formatValue = (value: unknown): string => { return `Unknown value: ${value}`; }; -export const formatTypeAndValue = (value: unknown, actual: Primitive) => { +export const formatTypeAndValue = ( + value: Primitive | readonly unknown[] | Record, + actual: Primitive +) => { if (value === null) { return 'null'; } @@ -44,23 +47,12 @@ export const formatTypeAndValue = (value: unknown, actual: Primitive) => { } if (typeof value === 'function') { - return 'function'; + return `${actual ? 'different ' : ''}function`; } if (Array.isArray(value)) { - return (actual ? 'different ' : '') + 'array of ' + value.length + ' items'; + return `${actual ? 'different ' : ''}array (${JSON.stringify(value)})`; } - if (typeof value === 'string') { - return ( - (actual ? 'different ' : '') + 'string of ' + value.length + ' chars' - ); - } - - if (typeof value === 'object') { - return (actual ? 'different ' : '') + 'object'; - } - - const digits = value.toString().replace(/[^0-9]/g, '').length; - return (actual ? 'different ' : '') + `${digits} digit number`; + return `${actual ? 'different ' : ''}${typeof value} (${JSON.stringify(value)})`; }; From 527dd02eebcced301a50b18d492f0903e6fa2b05 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Jun 2024 17:47:40 +0100 Subject: [PATCH 03/10] Further formatting improvements --- src/game/utils.ts | 8 ++++---- src/game/verifier.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/game/utils.ts b/src/game/utils.ts index b098e02..b4f98dd 100644 --- a/src/game/utils.ts +++ b/src/game/utils.ts @@ -36,7 +36,7 @@ export const formatValue = (value: unknown): string => { export const formatTypeAndValue = ( value: Primitive | readonly unknown[] | Record, - actual: Primitive + isResult: Primitive ) => { if (value === null) { return 'null'; @@ -47,12 +47,12 @@ export const formatTypeAndValue = ( } if (typeof value === 'function') { - return `${actual ? 'different ' : ''}function`; + return `${isResult ? 'different ' : ''}function`; } if (Array.isArray(value)) { - return `${actual ? 'different ' : ''}array (${JSON.stringify(value)})`; + return `array ${formatValue(value)}`; } - return `${actual ? 'different ' : ''}${typeof value} (${JSON.stringify(value)})`; + return `${typeof value} ${formatValue(value)}`; }; diff --git a/src/game/verifier.ts b/src/game/verifier.ts index 7aae577..0d7f9a3 100644 --- a/src/game/verifier.ts +++ b/src/game/verifier.ts @@ -2,7 +2,7 @@ import lodash from 'lodash'; import { readFileSync } from 'fs'; import { runInNewContext } from 'vm'; -import { formatTypeAndValue } from './utils.js'; +import { formatTypeAndValue, formatValue } from './utils.js'; import { challenges } from '../challenges/index.js'; import { Primitive } from '../challenges/types.js'; @@ -77,7 +77,7 @@ process.on('message', (entry: VerifyJob) => { )} but received ${formatTypeAndValue( result, true - )} when supplied with ${formatTypeAndValue(assertion.input, false)}` + )} when supplied with arguments: ${assertion.input.map((input) => formatValue(input)).join(', ')}` ); } }); From bdd44dbf74d67f7a4ce025b66a3ad49d13ebd27e Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Jun 2024 17:50:30 +0100 Subject: [PATCH 04/10] Include vscode dir and prevent auto formatting on save (affects solutions) --- .gitignore | 1 - .vscode/settings.json | 5 +++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 41331fa..5cad55b 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,3 @@ results npm-debug.log node_modules/ -/.vscode/* diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..4815fbc --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib", + "editor.formatOnSave": false, + "editor.codeActionsOnSave": [] +} From 5cad5d6d5d9eb7ab1621c1ef50c487b95cec64bf Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Jun 2024 17:52:53 +0100 Subject: [PATCH 05/10] Remove useless context from sort challenge --- src/challenges/c2-sort-the-numbers/index.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/challenges/c2-sort-the-numbers/index.ts b/src/challenges/c2-sort-the-numbers/index.ts index 8a86989..e42fa2b 100644 --- a/src/challenges/c2-sort-the-numbers/index.ts +++ b/src/challenges/c2-sort-the-numbers/index.ts @@ -1,11 +1,5 @@ import type { Challenge } from '../types.js'; -class ArrayNoSort extends Array { - public override sort() { - return ['allowed', 'no', 'sort'] as unknown as this; - } -} - const challenge: Challenge<[arr: readonly number[]], readonly number[]> = { title: 'Sort The Numbers', description: @@ -20,9 +14,6 @@ const challenge: Challenge<[arr: readonly number[]], readonly number[]> = { output: [1, 1, 2, 10, 12, 16, 22, 23, 33, 34, 65, 150, 250, 300], }, ], - context: { - Array: ArrayNoSort, - }, }; export default challenge; From 1f404f1200bf76ebcb635581ad0540c783091569 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Jun 2024 17:53:21 +0100 Subject: [PATCH 06/10] Include challenge context when running submission --- src/game/verifier.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/game/verifier.ts b/src/game/verifier.ts index 0d7f9a3..b448ca6 100644 --- a/src/game/verifier.ts +++ b/src/game/verifier.ts @@ -26,6 +26,7 @@ process.on('message', (entry: VerifyJob) => { const script = readFileSync(entry.file, 'utf8'); const context: { play?: unknown; module: { exports: unknown } } = { + ...challenge.context, module: { exports: {}, }, From 81b080b743cfef9bd8546cd462b642ba97097570 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Jun 2024 17:55:31 +0100 Subject: [PATCH 07/10] "eval is not the answer you're looking for" --- src/challenges/c5-add/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/challenges/c5-add/index.ts b/src/challenges/c5-add/index.ts index 59614e6..2840581 100644 --- a/src/challenges/c5-add/index.ts +++ b/src/challenges/c5-add/index.ts @@ -23,7 +23,7 @@ const challenge: Challenge<[input: [number, number]], number> = { }, ], context: { - eval: () => 42, + eval: () => "eval is not the answer you're looking for", }, assertRules: (playString) => { if (playString.includes('+')) { From 5169697181eb1a1d1097d71b4ec48679960d9816 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Jun 2024 18:03:28 +0100 Subject: [PATCH 08/10] Include actual error when unknown --- src/game/verifier.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/verifier.ts b/src/game/verifier.ts index b448ca6..dcfa95e 100644 --- a/src/game/verifier.ts +++ b/src/game/verifier.ts @@ -89,7 +89,7 @@ process.on('message', (entry: VerifyJob) => { ? err : err instanceof Error ? err.message - : 'Unknown error', + : `Unknown error ${err}`, valid: false, }); } From 478a183b69038afef0cc32063f65e447666efec0 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Jun 2024 18:05:16 +0100 Subject: [PATCH 09/10] Add ability to run code before submissions --- src/challenges/types.ts | 1 + src/game/verifier.ts | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/challenges/types.ts b/src/challenges/types.ts index 64f0a5d..abdfd42 100644 --- a/src/challenges/types.ts +++ b/src/challenges/types.ts @@ -31,4 +31,5 @@ export interface Challenge< assertRules?: (playString: string) => void; context?: Record; timeLimitMinutes?: number; + runBefore?: () => void; } diff --git a/src/game/verifier.ts b/src/game/verifier.ts index dcfa95e..e11cd1b 100644 --- a/src/game/verifier.ts +++ b/src/game/verifier.ts @@ -28,7 +28,9 @@ process.on('message', (entry: VerifyJob) => { const context: { play?: unknown; module: { exports: unknown } } = { ...challenge.context, module: { - exports: {}, + exports: { + runBefore: challenge.runBefore, + }, }, }; @@ -39,6 +41,15 @@ process.on('message', (entry: VerifyJob) => { runInNewContext(toRun, context); + if ( + typeof context.module.exports === 'object' && + !!context.module.exports && + hasKey(context.module.exports, 'runBefore') && + typeof context.module.exports.runBefore === 'function' + ) { + context.module.exports.runBefore(); + } + const play = typeof context.module.exports === 'function' ? context.module.exports From d3af4b306c1d38263e178d8644efb8b833dc0429 Mon Sep 17 00:00:00 2001 From: Jake 'Sid' Smith Date: Sun, 23 Jun 2024 18:20:12 +0100 Subject: [PATCH 10/10] Remove unnecessary if statement --- src/game/utils.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/game/utils.ts b/src/game/utils.ts index b4f98dd..0a59134 100644 --- a/src/game/utils.ts +++ b/src/game/utils.ts @@ -42,10 +42,6 @@ export const formatTypeAndValue = ( return 'null'; } - if (typeof value === 'undefined') { - return 'undefined'; - } - if (typeof value === 'function') { return `${isResult ? 'different ' : ''}function`; }