153 lines
6.8 KiB
Markdown
153 lines
6.8 KiB
Markdown
Here is Claude's plan:
|
|
╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌
|
|
이터레이션 1: 괄호 음수 분배 문제 풀이 기능
|
|
|
|
Context
|
|
|
|
완전 초기 상태(코드 없음)에서 바이브 코딩 방식으로 시작. DB·인증·Redis 없이 프론트엔드와 문제 생성
|
|
엔진만으로 첫 기능을 동작 가능한 상태까지 만든다.
|
|
|
|
---
|
|
단계별 접근법 (바이브 코딩)
|
|
|
|
각 단계가 독립적으로 실행·확인 가능한 단위로 나뉜다. 다음 단계로 넘어가기 전에 해당 단계가 정상
|
|
동작하는지 함께 확인한다.
|
|
|
|
┌──────┬──────────────────────────────┬────────────────────────────────────┐
|
|
│ 단계 │ 내용 │ 완료 기준 │
|
|
├──────┼──────────────────────────────┼────────────────────────────────────┤
|
|
│ 1 │ 프로젝트 초기화 │ pnpm dev 실행 시 Next.js 기본 화면 │
|
|
├──────┼──────────────────────────────┼────────────────────────────────────┤
|
|
│ 2 │ 문제 생성 엔진 + 단위 테스트 │ pnpm test 통과 │
|
|
├──────┼──────────────────────────────┼────────────────────────────────────┤
|
|
│ 3 │ KaTeX 수식 렌더링 컴포넌트 │ 브라우저에서 수식 정상 표시 │
|
|
├──────┼──────────────────────────────┼────────────────────────────────────┤
|
|
│ 4 │ Zustand 게임 상태 │ store에서 문제 생성·채점 동작 │
|
|
├──────┼──────────────────────────────┼────────────────────────────────────┤
|
|
│ 5 │ 게임 UI 조립 │ 문제 풀이 전체 흐름 플레이 가능 │
|
|
└──────┴──────────────────────────────┴────────────────────────────────────┘
|
|
|
|
---
|
|
1단계: 프로젝트 초기화
|
|
|
|
pnpm create next-app@14 . --typescript --tailwind --eslint --app --no-src-dir --import-alias "@/*"
|
|
pnpm add zustand katex react-katex framer-motion clsx tailwind-merge
|
|
pnpm add -D @types/katex vitest @vitejs/plugin-react jsdom @testing-library/react
|
|
|
|
app/layout.tsx에 추가:
|
|
import 'katex/dist/katex.min.css'
|
|
|
|
---
|
|
2단계: 문제 생성 엔진
|
|
|
|
lib/engine/types.ts
|
|
|
|
interface ParenthesisSignProblem {
|
|
id: string
|
|
multiplier: number // 항상 음수 (-1 ~ -9)
|
|
a: number // 괄호 안 첫째 항 (1 ~ 9)
|
|
operator: '+' | '-'
|
|
b: number // 괄호 안 둘째 항 (1 ~ 9)
|
|
distributedA: number // multiplier * a
|
|
distributedB: number // multiplier * (op==='-' ? -b : b)
|
|
latexBefore: string // 문제 수식
|
|
latexAfter: string // 정답 수식
|
|
}
|
|
interface UserAnswer { a: number; b: number }
|
|
interface GradeResult { correct: boolean; correctAnswer: [number, number] }
|
|
|
|
lib/engine/parenthesis-sign.ts
|
|
|
|
핵심 로직:
|
|
- multiplier: -9 ~ -1 (음수 강제)
|
|
- a, b: 1 ~ 9, a ≠ b
|
|
- distributedB 계산: operator === '-' 이면 multiplier * (-b), 아니면 multiplier * b
|
|
- KaTeX 빌드: -2(3 - 6) → 정답: -6 + 12
|
|
|
|
함수 목록:
|
|
- generateProblem(): ParenthesisSignProblem
|
|
- generateSession(count: number): ParenthesisSignProblem[] (중복 방지)
|
|
- gradeAnswer(problem, answer): GradeResult
|
|
|
|
테스트 파일: lib/engine/parenthesis-sign.test.ts
|
|
|
|
---
|
|
3단계: 수식 렌더링 컴포넌트
|
|
|
|
components/math/KatexRenderer.tsx ('use client')
|
|
|
|
- props: latex: string, displayMode?: boolean
|
|
- react-katex의 InlineMath / BlockMath 래핑
|
|
|
|
components/math/ExpressionDisplay.tsx
|
|
|
|
- props: problem, showAnswer?: boolean
|
|
- showAnswer=false: latexBefore 표시
|
|
- showAnswer=true: latexBefore → latexAfter (Framer Motion fade-in)
|
|
|
|
---
|
|
4단계: Zustand Store
|
|
|
|
store/gameStore.ts
|
|
|
|
interface GameState {
|
|
session: { problems: ParenthesisSignProblem[]; currentIndex: number; results: (GradeResult|null)[] }
|
|
| null
|
|
initSession: (count?: number) => void // 기본 10문제
|
|
submitAnswer: (answer: UserAnswer) => void
|
|
nextProblem: () => void
|
|
resetSession: () => void
|
|
// 셀렉터
|
|
currentProblem: () => ParenthesisSignProblem | null
|
|
currentResult: () => GradeResult | null
|
|
isComplete: () => boolean
|
|
score: () => { correct: number; total: number }
|
|
}
|
|
|
|
---
|
|
5단계: 게임 UI 조립
|
|
|
|
게임 컴포넌트
|
|
|
|
- components/game/AnswerInput.tsx: 두 개의 숫자 입력 (distributedA, distributedB), Enter 제출 지원
|
|
- components/game/FeedbackBanner.tsx: 정답(초록)/오답(빨강) + Framer Motion 슬라이드 인
|
|
- components/game/ProgressBar.tsx: n/total 진행 표시
|
|
- components/game/ScoreSummary.tsx: 최종 점수 + 다시 시작 버튼
|
|
|
|
페이지
|
|
|
|
- app/(game)/play/page.tsx: Server Component 래퍼
|
|
- app/(game)/play/PlayClient.tsx ('use client'): 상태에 따라 분기 렌더링
|
|
session===null → initSession()
|
|
!isComplete() → 문제 풀이 UI
|
|
isComplete() → ScoreSummary
|
|
- app/page.tsx: "연습 시작" → /play 이동
|
|
|
|
---
|
|
화면 흐름
|
|
|
|
app/page.tsx (시작)
|
|
→ (game)/play/PlayClient.tsx
|
|
├─ ProgressBar
|
|
├─ ExpressionDisplay (문제 수식)
|
|
├─ AnswerInput (두 항 입력)
|
|
├─ FeedbackBanner (제출 후)
|
|
├─ "다음 문제" 버튼
|
|
└─ [완료] ScoreSummary → "다시 시작"
|
|
|
|
---
|
|
검증 방법
|
|
|
|
1. pnpm test → 엔진 단위 테스트 전체 통과
|
|
2. pnpm dev → 브라우저에서 수식 렌더링 확인
|
|
3. 10문제 전체 풀이 → 점수 화면 확인
|
|
4. 오답 입력 → 오답 피드백 및 정답 표시 확인
|
|
5. "다시 시작" → 새 세션 생성 확인
|
|
|
|
---
|
|
이번 이터레이션에서 제외
|
|
|
|
- DB(MariaDB), Redis, NextAuth (2차 이터레이션)
|
|
- 유형 선택 / 모드 선택 화면 (3차 이터레이션)
|
|
- 스피드 퀴즈 모드 (4차 이터레이션)
|
|
- 미지수(x, y, z) 포함 문제 (파라미터 확장 이터레이션) |