From facdf9357e576f6d47e7dd23f4f7b2b34f6a8d30 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 17 Mar 2025 22:19:18 +0900 Subject: commit files --- src/components/App.tsx | 72 +++++++++++++++++++++++++++++++++++ src/components/FuncExpectedAnswer.tsx | 59 ++++++++++++++++++++++++++++ src/components/FuncMyAnswer.tsx | 32 ++++++++++++++++ src/components/QuizGroupSection.tsx | 19 +++++++++ src/components/QuizSection.tsx | 19 +++++++++ 5 files changed, 201 insertions(+) create mode 100644 src/components/App.tsx create mode 100644 src/components/FuncExpectedAnswer.tsx create mode 100644 src/components/FuncMyAnswer.tsx create mode 100644 src/components/QuizGroupSection.tsx create mode 100644 src/components/QuizSection.tsx (limited to 'src/components') diff --git a/src/components/App.tsx b/src/components/App.tsx new file mode 100644 index 0000000..aa2a386 --- /dev/null +++ b/src/components/App.tsx @@ -0,0 +1,72 @@ +import type { QuizGroup } from "../quiz"; +import QuizGroupSection from "./QuizGroupSection"; + +type Props = { + quizGroups: QuizGroup[]; +}; + +function App({ quizGroups }: Props) { + return ( + + + + + + + + +
+
+

+ PHPerKaigi 2025 の PHPer チャレンジ企画において、 + デジタルサーカス株式会社 + から出題するトークン問題です (作問{" "} + @nsfisis)。 +

+

+ それぞれの問題に、PHP の標準関数がひとつ設定されています。 + 好きな引数を渡すと実行されます。その実行結果を見て、何の関数かを当ててください。 +

+ {quizGroups.map((group) => ( + + ))} +
+
+ ); +} + +export default App; diff --git a/src/components/FuncExpectedAnswer.tsx b/src/components/FuncExpectedAnswer.tsx new file mode 100644 index 0000000..f412ba5 --- /dev/null +++ b/src/components/FuncExpectedAnswer.tsx @@ -0,0 +1,59 @@ +import type { Quiz } from "../quiz"; +import { execPHP } from "../exec_php"; +import React, { useState, useEffect } from "react"; +import { useDebounce } from "use-debounce"; + +type Props = { + quiz: Quiz; +}; + +function FuncExpectedAnswer({ quiz }: Props) { + const [argument, setArgument] = useState("123"); + const [debouncedArgument] = useDebounce(argument, 1000); + const [result, setResult] = useState(""); + const [loading, setLoading] = useState(true); + + const handleArgumentChange = (e: React.ChangeEvent) => { + setArgument(e.target.value); + }; + + useEffect(() => { + if (debouncedArgument === "") { + setResult(""); + return; + } + + setLoading(true); + setResult(""); + + const code = ` + function f($x) { + return ${quiz.func}($x); + } + try { + var_dump(f(${debouncedArgument})); + } catch (\\Throwable $e) { + echo $e->getMessage(), PHP_EOL; + } + `; + + execPHP(code).then((result) => { + const output = result.stdout + result.stderr; + setResult(output.replaceAll(quiz.func, "")); + setLoading(false); + }); + }, [debouncedArgument, quiz.func]); + + return ( +
+ + {`f(`} + + {`)`} + + は {loading ? "running..." : result} を返す。 +
+ ); +} + +export default FuncExpectedAnswer; diff --git a/src/components/FuncMyAnswer.tsx b/src/components/FuncMyAnswer.tsx new file mode 100644 index 0000000..63cd427 --- /dev/null +++ b/src/components/FuncMyAnswer.tsx @@ -0,0 +1,32 @@ +import type { Quiz } from "../quiz"; +import React, { useState } from "react"; +import { useDebounce } from "use-debounce"; + +type Props = { + quiz: Quiz; +}; + +const INITIAL_ANSWER = "your_answer"; + +function FuncMyAnswer({ quiz }: Props) { + const [answer, setAnswer] = useState(INITIAL_ANSWER); + const [debouncedAnswer] = useDebounce(answer, 500); + const hasAnyAnswer = debouncedAnswer !== INITIAL_ANSWER; + const isCorrectAnswer = debouncedAnswer === quiz.func; + + const handleAnswerChange = (e: React.ChangeEvent) => { + setAnswer(e.target.value); + }; + + return ( +
+ この関数は? + +

+ {hasAnyAnswer && (isCorrectAnswer ? `正解!${quiz.message}` : "不正解")} +

+
+ ); +} + +export default FuncMyAnswer; diff --git a/src/components/QuizGroupSection.tsx b/src/components/QuizGroupSection.tsx new file mode 100644 index 0000000..b2bbee7 --- /dev/null +++ b/src/components/QuizGroupSection.tsx @@ -0,0 +1,19 @@ +import type { QuizGroup } from "../quiz"; +import QuizSection from "./QuizSection"; + +type Props = { + quizGroup: QuizGroup; +}; + +function QuizGroupSection({ quizGroup }: Props) { + return ( +
+

{quizGroup.label}

+ {quizGroup.quizzes.map((quiz) => ( + + ))} +
+ ); +} + +export default QuizGroupSection; diff --git a/src/components/QuizSection.tsx b/src/components/QuizSection.tsx new file mode 100644 index 0000000..27dc384 --- /dev/null +++ b/src/components/QuizSection.tsx @@ -0,0 +1,19 @@ +import type { Quiz } from "../quiz"; +import FuncExpectedAnswer from "./FuncExpectedAnswer"; +import FuncMyAnswer from "./FuncMyAnswer"; + +type Props = { + quiz: Quiz; +}; + +function QuizSection({ quiz }: Props) { + return ( +
+

{quiz.label}

+ + +
+ ); +} + +export default QuizSection; -- cgit v1.2.3-70-g09d2