From 22049f106ad30046419e8a338b63c0b41e92f3c6 Mon Sep 17 00:00:00 2001 From: tatehito <48908346+Tatehito@users.noreply.github.com> Date: Tue, 13 Feb 2024 08:08:55 +0900 Subject: [PATCH] feat: Add step problem (#34) --- .../[problemId]/CheckpointProblem.tsx | 59 ++++++------ .../[problemId]/ExecutionResultProblem.tsx | 24 ++--- .../problems/[problemId]/StepProblem.tsx | 94 +++++++++++++++++++ .../(withAuth)/problems/[problemId]/page.tsx | 57 ++++++++++- src/problems/problemData.ts | 3 +- 5 files changed, 189 insertions(+), 48 deletions(-) create mode 100644 src/app/(withAuth)/problems/[problemId]/StepProblem.tsx diff --git a/src/app/(withAuth)/problems/[problemId]/CheckpointProblem.tsx b/src/app/(withAuth)/problems/[problemId]/CheckpointProblem.tsx index 5d953304..52e0b7a8 100644 --- a/src/app/(withAuth)/problems/[problemId]/CheckpointProblem.tsx +++ b/src/app/(withAuth)/problems/[problemId]/CheckpointProblem.tsx @@ -1,37 +1,35 @@ 'use client'; import { Box, Button, Flex, HStack, VStack } from '@chakra-ui/react'; -import { useEffect, useRef, useState } from 'react'; +import { useRef } from 'react'; import { SyntaxHighlighter } from '../../../../components/organisms/SyntaxHighlighter'; import type { TurtleGraphicsHandle } from '../../../../components/organisms/TurtleGraphics'; import { TurtleGraphics } from '../../../../components/organisms/TurtleGraphics'; -import { generateProgram } from '../../../../problems/problemData'; import type { ProblemType } from '../../../../types'; -import { getLanguageIdFromSessionStorage } from '../../../lib/SessionStorage'; interface CheckpointProblemProps { - problemId: string; + problemProgram: string; + selectedLanguageId: string; + checkPointLines: number[]; setStep: (step: ProblemType) => void; + beforeCheckPointLine: number; + setBeforeCheckPointLine: (line: number) => void; + currentCheckPointLine: number; + setCurrentCheckPointLine: (line: number) => void; } -export const CheckpointProblem: React.FC = ({ problemId }) => { +export const CheckpointProblem: React.FC = ({ + beforeCheckPointLine, + checkPointLines, + currentCheckPointLine, + problemProgram, + selectedLanguageId, + setBeforeCheckPointLine, + setCurrentCheckPointLine, + setStep, +}) => { const turtleGraphicsRef = useRef(null); - const [selectedLanguageId, setSelectedLanguageId] = useState(''); - - // TODO: チェックポイントを取得する処理が実装できたら置き換える - const getCheckPointLines = [2, 4]; - const [problemProgram, setProblemProgram] = useState(''); - const [beforeCheckPointLine, setBeforeCheckPointLine] = useState(1); - const [currentCheckPointLine, setCurrentCheckPointLine] = useState(getCheckPointLines[0]); - - useEffect(() => { - setSelectedLanguageId(getLanguageIdFromSessionStorage()); - }, []); - - useEffect(() => { - setProblemProgram(generateProgram(problemId, selectedLanguageId)); - }, [problemId, selectedLanguageId]); const handleClickResetButton = (): void => { turtleGraphicsRef.current?.init(); @@ -42,15 +40,22 @@ export const CheckpointProblem: React.FC = ({ problemId // TODO: 一旦アラートで表示 if (isCorrect) { - alert('正解です'); - - if (currentCheckPointLine === getCheckPointLines.at(-1)) return; - setBeforeCheckPointLine(currentCheckPointLine); - setCurrentCheckPointLine(getCheckPointLines[getCheckPointLines.indexOf(currentCheckPointLine) + 1]); + + if (currentCheckPointLine === checkPointLines.at(-1)) { + // 最終チェックポイントを正解した場合はその次の行からステップ問題に移行 + alert('正解です。このチェックポイントから1行ずつ回答してください'); + setCurrentCheckPointLine(currentCheckPointLine + 1); + setStep('step'); + } else { + alert('正解です。次のチェックポイントに進みます'); + setCurrentCheckPointLine(checkPointLines[checkPointLines.indexOf(currentCheckPointLine) + 1]); + } } else { - alert('不正解です'); - // setStep('step'); + // 不正解の場合は最後に正解したチェックポイントからステップ問題に移行 + alert('不正解です。最後に正解したチェックポイントから1行ずつ回答してください'); + setCurrentCheckPointLine(beforeCheckPointLine + 1); + setStep('step'); } }; diff --git a/src/app/(withAuth)/problems/[problemId]/ExecutionResultProblem.tsx b/src/app/(withAuth)/problems/[problemId]/ExecutionResultProblem.tsx index d5634228..45fe0166 100644 --- a/src/app/(withAuth)/problems/[problemId]/ExecutionResultProblem.tsx +++ b/src/app/(withAuth)/problems/[problemId]/ExecutionResultProblem.tsx @@ -1,29 +1,25 @@ 'use client'; import { Box, Button, Flex, HStack, VStack } from '@chakra-ui/react'; -import { useEffect, useState, useRef } from 'react'; +import { useRef } from 'react'; import { SyntaxHighlighter } from '../../../../components/organisms/SyntaxHighlighter'; import type { TurtleGraphicsHandle } from '../../../../components/organisms/TurtleGraphics'; import { TurtleGraphics } from '../../../../components/organisms/TurtleGraphics'; -import { generateProgram } from '../../../../problems/problemData'; import type { ProblemType } from '../../../../types'; -import { getLanguageIdFromSessionStorage } from '../../../lib/SessionStorage'; interface ExecutionResultProblemProps { - problemId: string; + problemProgram: string; + selectedLanguageId: string; setStep: (step: ProblemType) => void; } -export const ExecutionResultProblem: React.FC = ({ problemId, setStep }) => { +export const ExecutionResultProblem: React.FC = ({ + problemProgram, + selectedLanguageId, + setStep, +}) => { const turtleGraphicsRef = useRef(null); - const [selectedLanguageId, setSelectedLanguageId] = useState(''); - - useEffect(() => { - setSelectedLanguageId(getLanguageIdFromSessionStorage()); - }, []); - - const problemProgram = generateProgram(problemId, selectedLanguageId); const handleClickResetButton = (): void => { turtleGraphicsRef.current?.init(); @@ -34,9 +30,9 @@ export const ExecutionResultProblem: React.FC = ({ // TODO: 一旦アラートで表示 if (isCorrect) { - alert('正解です'); + alert('正解です。この問題は終了です'); } else { - alert('不正解です'); + alert('不正解です。チェックポイントごとに回答してください'); setStep('checkpoint'); } }; diff --git a/src/app/(withAuth)/problems/[problemId]/StepProblem.tsx b/src/app/(withAuth)/problems/[problemId]/StepProblem.tsx new file mode 100644 index 00000000..c061135e --- /dev/null +++ b/src/app/(withAuth)/problems/[problemId]/StepProblem.tsx @@ -0,0 +1,94 @@ +'use client'; + +import { Box, Button, Flex, HStack, VStack } from '@chakra-ui/react'; +import { useRef } from 'react'; + +import { SyntaxHighlighter } from '../../../../components/organisms/SyntaxHighlighter'; +import type { TurtleGraphicsHandle } from '../../../../components/organisms/TurtleGraphics'; +import { TurtleGraphics } from '../../../../components/organisms/TurtleGraphics'; + +interface StepProblemProps { + beforeCheckPointLine: number; + currentCheckPointLine: number; + problemProgram: string; + selectedLanguageId: string; + setBeforeCheckPointLine: (line: number) => void; + setCurrentCheckPointLine: (line: number) => void; +} + +export const StepProblem: React.FC = ({ + beforeCheckPointLine, + currentCheckPointLine, + problemProgram, + selectedLanguageId, + setBeforeCheckPointLine, + setCurrentCheckPointLine, +}) => { + const turtleGraphicsRef = useRef(null); + + const handleClickResetButton = (): void => { + turtleGraphicsRef.current?.init(); + }; + + const handleClickAnswerButton = (): void => { + const isCorrect = turtleGraphicsRef.current?.isCorrect(); + + // TODO: 一旦アラートで表示 + if (isCorrect) { + const problemProgramLines = problemProgram.split('\n').length; + + if (currentCheckPointLine === problemProgramLines) { + alert('正解です。この問題は終了です'); + } else { + alert('正解です。次の行に進みます'); + setBeforeCheckPointLine(currentCheckPointLine); + setCurrentCheckPointLine(currentCheckPointLine + 1); + } + } else { + alert('不正解です。もう一度回答してください'); + } + }; + + return ( + + + 茶色にハイライトされている行における盤面を作成してください。 + 青色のハイライト時点の実行結果 + + + + 茶色のハイライト時点の実行結果 + + + + + + + + + + + + + + + + ); +}; diff --git a/src/app/(withAuth)/problems/[problemId]/page.tsx b/src/app/(withAuth)/problems/[problemId]/page.tsx index 61e6ee5b..31a773e8 100644 --- a/src/app/(withAuth)/problems/[problemId]/page.tsx +++ b/src/app/(withAuth)/problems/[problemId]/page.tsx @@ -2,24 +2,71 @@ import { Heading, VStack } from '@chakra-ui/react'; import type { NextPage } from 'next'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; -import { programIdToName } from '../../../../problems/problemData'; +import { generateProgram, programIdToName } from '../../../../problems/problemData'; import type { ProblemType } from '../../../../types'; +import { getLanguageIdFromSessionStorage } from '../../../lib/SessionStorage'; import { CheckpointProblem } from './CheckpointProblem'; import { ExecutionResultProblem } from './ExecutionResultProblem'; +import { StepProblem } from './StepProblem'; const ProblemPage: NextPage<{ params: { problemId: string } }> = ({ params }) => { + const problemId = params.problemId; + // TODO: チェックポイントを取得する処理が実装できたら置き換える + const checkPointLines = [1, 4]; + + const [selectedLanguageId, setSelectedLanguageId] = useState(''); + const [problemProgram, setProblemProgram] = useState(''); const [step, setStep] = useState('normal'); + const [beforeCheckPointLine, setBeforeCheckPointLine] = useState(0); + const [currentCheckPointLine, setCurrentCheckPointLine] = useState(checkPointLines[0]); + + useEffect(() => { + setSelectedLanguageId(getLanguageIdFromSessionStorage()); + }, []); + + useEffect(() => { + setProblemProgram(generateProgram(problemId, selectedLanguageId)); + }, [problemId, selectedLanguageId]); const ProblemComponent: React.FC = () => { switch (step) { case 'normal': { - return ; + return ( + + ); } case 'checkpoint': { - return ; + return ( + + ); + } + case 'step': { + return ( + + ); } } }; @@ -27,7 +74,7 @@ const ProblemPage: NextPage<{ params: { problemId: string } }> = ({ params }) => return (
- {programIdToName[params.problemId]} + {programIdToName[problemId]}
diff --git a/src/problems/problemData.ts b/src/problems/problemData.ts index 4399b128..28cf861e 100644 --- a/src/problems/problemData.ts +++ b/src/problems/problemData.ts @@ -42,8 +42,7 @@ character1.moveForward(); character1.moveForward(); character1.moveForward(); character1.moveForward(); -character1.moveForward(); -` || programIdToLanguageIdToProgram[programId][languageId] +character1.moveForward();` || programIdToLanguageIdToProgram[programId][languageId] ); }