From 0a9e8c6f8debb3af7a4f0e634a386fd3ba72db55 Mon Sep 17 00:00:00 2001 From: taisii Date: Sat, 24 Feb 2024 16:09:44 +0900 Subject: [PATCH 1/2] . --- src/app/lib/solveProblem.ts | 80 +++++++++++++++++++++++++++++++++++++ src/problems/problemData.ts | 16 ++++++++ 2 files changed, 96 insertions(+) diff --git a/src/app/lib/solveProblem.ts b/src/app/lib/solveProblem.ts index 8715fe97..2d4d1e24 100644 --- a/src/app/lib/solveProblem.ts +++ b/src/app/lib/solveProblem.ts @@ -10,6 +10,86 @@ export function parseProgram(program: string): string[] { .filter((line) => line !== ''); } +export function instrumentCode(code: string): string { + // generateCodeからコードを受け取って、トレースできるコードを返す関数 + const sidRegex = /\/\* (\d+) \*\//; + const assignmentRegex = /([\w.]+)(?: = |\+\+|--)/; + const modifiedCodeLines: string[] = []; + const lines = code.split('\n'); + + for (const line of lines) { + const trimmedLine = line.trimStart(); + let modifiedCodeLine = trimmedLine; + const statementMatch = trimmedLine.match(sidRegex); + if (statementMatch) { + const sid = statementMatch[1]; + + // ' = 'を含むline + const assignmentMatch = line.match(assignmentRegex); + if (assignmentMatch) { + const variableName = assignmentMatch[1].trim(); + modifiedCodeLine = modifiedCodeLine.replace(sidRegex, `log(${sid}, '${variableName}', ${variableName});`); + } + } + modifiedCodeLines.push(modifiedCodeLine); + } + return modifiedCodeLines.join('\n'); +} + +type Trace = { + sid: number; + variableName: string; + variableValue: string; +}; + +export async function traceCode(code: string): Promise { + const Character = CharacterClass; // eslint-disable-line + const Board = BoardClass; // eslint-disable-line + const codeForTracing = ` +const traceList = []; + +${code} + +function log(sid, variableName, variableValue) { + if (typeof value === 'number' && (!isFinite(value) || isNaN(value) || (modulo && value < 0))) { + process.exit(1); + } + traceList.push({ + sid, + variableName, + variableValue + }); +} + +JSON.stringify(traceList); +`.replaceAll(/\s+/g, ' '); + const ret: Trace[] = JSON.parse(eval(codeForTracing)); + console.log('variableList', traceToVariablesList(ret)); +} + +function traceToVariablesList(traceList: Trace[]): Variable[][] { + console.log(traceList); + const lineCount = traceList.at(-1)?.sid ?? 0; + const variablesList: Variable[][] = []; + console.log('variableList', variablesList); + let index = 0; + for (let i = 0; i < lineCount; i++) { + const variables = variablesList.at(-1) ?? ([] as Variable[]); + while (traceList[index].sid <= i) { + const { variableName, variableValue } = traceList[index]; + const variablesIndex = variables.findIndex((variable) => variable.name === variableName); + if (variablesIndex === -1) { + variables.push({ name: variableName, value: variableValue }); + } else { + variables[variablesIndex].value = variableValue; + } + index++; + } + variablesList.push(variables); + } + return variablesList; +} + export function executeEval(command: string): (CharacterVariable | Variable)[] { const Character = CharacterClass; // eslint-disable-line const Board = BoardClass; // eslint-disable-line diff --git a/src/problems/problemData.ts b/src/problems/problemData.ts index a131a84a..25f5f456 100644 --- a/src/problems/problemData.ts +++ b/src/problems/problemData.ts @@ -1,3 +1,5 @@ +import { instrumentCode, traceCode } from '../app/lib/solveProblem'; + export const courseIds = ['tuBeginner1', 'tuBeginner2']; export type CourseId = (typeof courseIds)[number]; @@ -36,6 +38,20 @@ export const courseIdToProgramIdLists: Record = { export function generateProgram(programId: ProgramId, languageId: LanguageId): string { // TODO(exKAZUu): 問題IDに紐づくプログラム(テンプレート)を取得して、乱数を使って具体的なプログラムを生成する。 + const code = `const bear = new Character(); /* 1 */ +bear.moveForward(); /* 2 */ +bear.turnLeft(); /* 3 */ +bear.upPen(); /* 4 */ +let i = 0; /* 5 */ +bear.moveForward(); /* 6 */ +const turtle = new Character({x: 3, y: 1, color: 'green'}); /* 7 */ +turtle.moveForward(); /* 8 */ +const foo = 'あいうえお'; /* 9 */ +var bar = 123; /* 10 */ +i = i + 1; /* 11 */ +turtle.moveForward(); /* 12 */ +turtle.moveForward(); /* 13 */`; + traceCode(instrumentCode(code)); return ( `const bear = new Character(); bear.moveForward(); From 460140e39b83b71d689dc86054db1c83ff7fef99 Mon Sep 17 00:00:00 2001 From: taisii Date: Mon, 26 Feb 2024 16:32:41 +0900 Subject: [PATCH 2/2] . --- src/app/lib/solveProblem.ts | 67 +++++++++++++++++++------------------ src/problems/problemData.ts | 22 ++---------- 2 files changed, 38 insertions(+), 51 deletions(-) diff --git a/src/app/lib/solveProblem.ts b/src/app/lib/solveProblem.ts index 2d4d1e24..2cf0c2f8 100644 --- a/src/app/lib/solveProblem.ts +++ b/src/app/lib/solveProblem.ts @@ -1,6 +1,7 @@ import type { CharacterVariable, History, SolveProblemResult, Variable } from '../../types'; import { Board as BoardClass } from './Board'; +import type { Character } from './Character'; import { Character as CharacterClass } from './Character'; export function parseProgram(program: string): string[] { @@ -28,6 +29,7 @@ export function instrumentCode(code: string): string { const assignmentMatch = line.match(assignmentRegex); if (assignmentMatch) { const variableName = assignmentMatch[1].trim(); + modifiedCodeLine = modifiedCodeLine.replace(sidRegex, `log(${sid}, '${variableName}', ${variableName});`); } } @@ -39,10 +41,10 @@ export function instrumentCode(code: string): string { type Trace = { sid: number; variableName: string; - variableValue: string; + variableValue: Character | string; }; -export async function traceCode(code: string): Promise { +export function traceCode(code: string): Trace[] { const Character = CharacterClass; // eslint-disable-line const Board = BoardClass; // eslint-disable-line const codeForTracing = ` @@ -64,28 +66,31 @@ function log(sid, variableName, variableValue) { JSON.stringify(traceList); `.replaceAll(/\s+/g, ' '); const ret: Trace[] = JSON.parse(eval(codeForTracing)); - console.log('variableList', traceToVariablesList(ret)); + return ret; } -function traceToVariablesList(traceList: Trace[]): Variable[][] { - console.log(traceList); +function traceToVariablesList(traceList: Trace[]): (CharacterVariable | Variable)[][] { const lineCount = traceList.at(-1)?.sid ?? 0; - const variablesList: Variable[][] = []; - console.log('variableList', variablesList); + const variablesList: (CharacterVariable | Variable)[][] = []; let index = 0; for (let i = 0; i < lineCount; i++) { - const variables = variablesList.at(-1) ?? ([] as Variable[]); + const variables = variablesList.at(-1) ?? ([] as (CharacterVariable | Variable)[]); while (traceList[index].sid <= i) { const { variableName, variableValue } = traceList[index]; const variablesIndex = variables.findIndex((variable) => variable.name === variableName); if (variablesIndex === -1) { - variables.push({ name: variableName, value: variableValue }); + if (variableValue instanceof CharacterClass) { + console.log('character'); + variables.push({ name: variableName, value: variableValue } as CharacterVariable); + } else { + variables.push({ name: variableName, value: variableValue } as Variable); + } } else { variables[variablesIndex].value = variableValue; } index++; } - variablesList.push(variables); + variablesList.push([...variables]); } return variablesList; } @@ -132,38 +137,36 @@ export function extractVariableNames(command: string): string[] { } export function solveProblem(program: string): SolveProblemResult { - const commands = parseProgram(program); const board = new BoardClass(); const histories: History[] = [{ step: 0, characterVariables: [], board, otherVariables: [] }]; - for (let i = 0; i < commands.length; i++) { - if (i < commands.length) { - let mergedCommand = ''; + const traceList = traceCode(instrumentCode(program)); + const variablesList = traceToVariablesList(traceList); - for (let j = 0; j <= i; j++) { - mergedCommand += commands[j]; - } + for (const variables of variablesList) { + console.log('variables', variables); + const characterVariables = selectCharacterVariables(variables); + const otherVariables = selectOtherVariables(variables); + console.log('characterVariables', characterVariables); + console.log('otherVariables', otherVariables); - const variables = executeEval(mergedCommand); - const characterVariables = selectCharacterVariables(variables); - const otherVariables = selectOtherVariables(variables); + const board = new BoardClass(); + for (const history of histories) { + if (!history.characterVariables) continue; - const board = new BoardClass(); - for (const history of histories) { - if (!history.characterVariables) continue; - - for (const character of history.characterVariables) { - board.updateGrid(character.value); - } + for (const character of history.characterVariables) { + board.updateGrid(character.value); } - for (const character of characterVariables) { - board.updateGrid(character.value as CharacterClass); - } - - histories.push({ step: histories.length + 1, characterVariables, board, otherVariables }); } + for (const character of characterVariables) { + board.updateGrid(character.value as CharacterClass); + } + + histories.push({ step: histories.length + 1, characterVariables, board, otherVariables }); } + console.log(histories); + const result: SolveProblemResult = { characterVariables: histories?.at(-1)?.characterVariables, otherVariables: histories?.at(-1)?.otherVariables, diff --git a/src/problems/problemData.ts b/src/problems/problemData.ts index 25f5f456..29cc30e7 100644 --- a/src/problems/problemData.ts +++ b/src/problems/problemData.ts @@ -1,5 +1,3 @@ -import { instrumentCode, traceCode } from '../app/lib/solveProblem'; - export const courseIds = ['tuBeginner1', 'tuBeginner2']; export type CourseId = (typeof courseIds)[number]; @@ -38,7 +36,8 @@ export const courseIdToProgramIdLists: Record = { export function generateProgram(programId: ProgramId, languageId: LanguageId): string { // TODO(exKAZUu): 問題IDに紐づくプログラム(テンプレート)を取得して、乱数を使って具体的なプログラムを生成する。 - const code = `const bear = new Character(); /* 1 */ + return ( + `const bear = new Character(); /* 1 */ bear.moveForward(); /* 2 */ bear.turnLeft(); /* 3 */ bear.upPen(); /* 4 */ @@ -50,22 +49,7 @@ const foo = 'あいうえお'; /* 9 */ var bar = 123; /* 10 */ i = i + 1; /* 11 */ turtle.moveForward(); /* 12 */ -turtle.moveForward(); /* 13 */`; - traceCode(instrumentCode(code)); - return ( - `const bear = new Character(); -bear.moveForward(); -bear.turnLeft(); -bear.upPen(); -let i = 0; -bear.moveForward(); -const turtle = new Character({x: 3, y: 1, color: 'green'}); -turtle.moveForward(); -const foo = 'あいうえお'; -var bar = 123; -i = i + 1; -turtle.moveForward(); -turtle.moveForward();` || programIdToLanguageIdToProgram[programId][languageId] +turtle.moveForward(); /* 13 */` || programIdToLanguageIdToProgram[programId][languageId] ); }