コミットを比較
1 コミット
feature/041
...
main
| 作成者 | SHA1 | 日付 | |
|---|---|---|---|
| e94720941c |
@@ -78,6 +78,8 @@ type GameSnapshot = {
|
|||||||
rejectedPostIds: Set<number>
|
rejectedPostIds: Set<number>
|
||||||
lastGuessQuestionCount: number
|
lastGuessQuestionCount: number
|
||||||
lastRejectedGuessId: number | null
|
lastRejectedGuessId: number | null
|
||||||
|
winningRunTargetId: number | null
|
||||||
|
winningRunStartAnswerCount: number | null
|
||||||
activeGuessId: number | null
|
activeGuessId: number | null
|
||||||
reviewGuessedPostId: number | null
|
reviewGuessedPostId: number | null
|
||||||
reviewCorrectPostId: number | null }
|
reviewCorrectPostId: number | null }
|
||||||
@@ -99,6 +101,8 @@ type StoredGekanatorGame = {
|
|||||||
rejectedPostIds: number[]
|
rejectedPostIds: number[]
|
||||||
lastGuessQuestionCount: number
|
lastGuessQuestionCount: number
|
||||||
lastRejectedGuessId: number | null
|
lastRejectedGuessId: number | null
|
||||||
|
winningRunTargetId?: number | null
|
||||||
|
winningRunStartAnswerCount?: number | null
|
||||||
activeGuessId: number | null
|
activeGuessId: number | null
|
||||||
reviewGuessedPostId: number | null
|
reviewGuessedPostId: number | null
|
||||||
reviewCorrectPostId: number | null
|
reviewCorrectPostId: number | null
|
||||||
@@ -126,6 +130,7 @@ const minQuestionsBeforeCertainGuess = 5
|
|||||||
const certainGuessPercent = 99.5
|
const certainGuessPercent = 99.5
|
||||||
const runnerUpMaxPercent = .5
|
const runnerUpMaxPercent = .5
|
||||||
const hardMaxQuestions = 80
|
const hardMaxQuestions = 80
|
||||||
|
const winningRunQuestionLimit = 3
|
||||||
const softenedAnswerWeight = .35
|
const softenedAnswerWeight = .35
|
||||||
const confidenceTemperature = 6
|
const confidenceTemperature = 6
|
||||||
const gameStorageKey = 'gekanator:game:v1'
|
const gameStorageKey = 'gekanator:game:v1'
|
||||||
@@ -191,6 +196,8 @@ const normalizeStoredGame = (game: StoredGekanatorGame): StoredGekanatorGame =>
|
|||||||
normalizeStoredQuestionId (questionId)),
|
normalizeStoredQuestionId (questionId)),
|
||||||
recoveredCandidatePosts: game.recoveredCandidatePosts ?? [],
|
recoveredCandidatePosts: game.recoveredCandidatePosts ?? [],
|
||||||
recoveryStepCount: game.recoveryStepCount ?? 0,
|
recoveryStepCount: game.recoveryStepCount ?? 0,
|
||||||
|
winningRunTargetId: game.winningRunTargetId ?? null,
|
||||||
|
winningRunStartAnswerCount: game.winningRunStartAnswerCount ?? null,
|
||||||
askedQuestionBank: game.askedQuestionBank?.map (question =>
|
askedQuestionBank: game.askedQuestionBank?.map (question =>
|
||||||
({
|
({
|
||||||
...question,
|
...question,
|
||||||
@@ -828,6 +835,135 @@ const chooseQuestion = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const directWinningRunExampleAnswerFor = (
|
||||||
|
question: GekanatorQuestion,
|
||||||
|
targetPost: Post,
|
||||||
|
): GekanatorAnswerValue | null =>
|
||||||
|
question.kind !== 'post_similarity'
|
||||||
|
? null
|
||||||
|
: question.exampleAnswers?.[String (targetPost.id) as `${ number }`] ?? null
|
||||||
|
|
||||||
|
|
||||||
|
const winningRunPriorityFor = (
|
||||||
|
question: GekanatorQuestion,
|
||||||
|
expected: GekanatorAnswerValue,
|
||||||
|
targetPost: Post,
|
||||||
|
): number | null => {
|
||||||
|
if (question.kind === 'post_similarity')
|
||||||
|
{
|
||||||
|
const directAnswer = directWinningRunExampleAnswerFor (question, targetPost)
|
||||||
|
if (directAnswer === null)
|
||||||
|
return null
|
||||||
|
if (expected === 'yes')
|
||||||
|
return 1
|
||||||
|
if (expected === 'no')
|
||||||
|
return 3
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expected === 'yes')
|
||||||
|
return 0
|
||||||
|
if (expected === 'no')
|
||||||
|
return 2
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const chooseWinningRunQuestion = ({
|
||||||
|
posts,
|
||||||
|
fallbackPosts,
|
||||||
|
questions,
|
||||||
|
targetPost,
|
||||||
|
scores,
|
||||||
|
answers,
|
||||||
|
askedIds,
|
||||||
|
gameSeed,
|
||||||
|
}: {
|
||||||
|
posts: Post[]
|
||||||
|
fallbackPosts: Post[]
|
||||||
|
questions: GekanatorQuestion[]
|
||||||
|
targetPost: Post
|
||||||
|
scores: Map<number, number>
|
||||||
|
answers: GekanatorAnswerLog[]
|
||||||
|
askedIds: Set<string>
|
||||||
|
gameSeed: string
|
||||||
|
}): GekanatorQuestion | null => {
|
||||||
|
const ranked = questions
|
||||||
|
.filter (question => {
|
||||||
|
if (askedIds.has (question.id))
|
||||||
|
return false
|
||||||
|
if (isQuestionHardFilteredAfterAnswers (question, answers))
|
||||||
|
return false
|
||||||
|
|
||||||
|
const expected = expectedAnswerForQuestion (question, targetPost)
|
||||||
|
return expected !== null && expected !== 'unknown'
|
||||||
|
})
|
||||||
|
.map (question => {
|
||||||
|
const expected = expectedAnswerForQuestion (question, targetPost)
|
||||||
|
const priority =
|
||||||
|
expected === null
|
||||||
|
? null
|
||||||
|
: winningRunPriorityFor (question, expected, targetPost)
|
||||||
|
if (priority === null)
|
||||||
|
return null
|
||||||
|
|
||||||
|
const yesCount = posts.filter (post => question.test (post)).length
|
||||||
|
const matchingCount =
|
||||||
|
expected === 'yes' || expected === 'partial'
|
||||||
|
? yesCount
|
||||||
|
: posts.length - yesCount
|
||||||
|
|
||||||
|
return {
|
||||||
|
question,
|
||||||
|
priority,
|
||||||
|
matchingCount }
|
||||||
|
})
|
||||||
|
.filter ((item): item is {
|
||||||
|
question: GekanatorQuestion
|
||||||
|
priority: number
|
||||||
|
matchingCount: number } => item !== null)
|
||||||
|
.sort ((a, b) => {
|
||||||
|
if (a.priority !== b.priority)
|
||||||
|
return a.priority - b.priority
|
||||||
|
|
||||||
|
if (a.matchingCount !== b.matchingCount)
|
||||||
|
return a.matchingCount - b.matchingCount
|
||||||
|
|
||||||
|
if (a.question.priorityWeight !== b.question.priorityWeight)
|
||||||
|
return b.question.priorityWeight - a.question.priorityWeight
|
||||||
|
|
||||||
|
return a.question.id.localeCompare (b.question.id)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (ranked.length > 0)
|
||||||
|
return ranked[0]?.question ?? null
|
||||||
|
|
||||||
|
return chooseQuestion ({
|
||||||
|
posts: fallbackPosts.length > 0 ? fallbackPosts : posts,
|
||||||
|
questions,
|
||||||
|
scores,
|
||||||
|
answers,
|
||||||
|
askedIds,
|
||||||
|
gameSeed })
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const isWinningRunActive = (
|
||||||
|
winningRunTargetId: number | null,
|
||||||
|
winningRunStartAnswerCount: number | null,
|
||||||
|
): boolean =>
|
||||||
|
winningRunTargetId !== null && winningRunStartAnswerCount !== null
|
||||||
|
|
||||||
|
|
||||||
|
const winningRunQuestionCount = (
|
||||||
|
answers: GekanatorAnswerLog[],
|
||||||
|
winningRunStartAnswerCount: number | null,
|
||||||
|
): number => winningRunStartAnswerCount === null
|
||||||
|
? 0
|
||||||
|
: Math.max (0, answers.length - winningRunStartAnswerCount)
|
||||||
|
|
||||||
|
|
||||||
const bestPost = (posts: Post[], scores: Map<number, number>): Post | null =>
|
const bestPost = (posts: Post[], scores: Map<number, number>): Post | null =>
|
||||||
posts
|
posts
|
||||||
.map (post => ({ post, score: scores.get (post.id) ?? 0 }))
|
.map (post => ({ post, score: scores.get (post.id) ?? 0 }))
|
||||||
@@ -896,6 +1032,10 @@ const GekanatorPage: FC = () => {
|
|||||||
storedGame?.lastGuessQuestionCount ?? 0)
|
storedGame?.lastGuessQuestionCount ?? 0)
|
||||||
const [lastRejectedGuessId, setLastRejectedGuessId] = useState<number | null> (
|
const [lastRejectedGuessId, setLastRejectedGuessId] = useState<number | null> (
|
||||||
storedGame?.lastRejectedGuessId ?? null)
|
storedGame?.lastRejectedGuessId ?? null)
|
||||||
|
const [winningRunTargetId, setWinningRunTargetId] = useState<number | null> (
|
||||||
|
storedGame?.winningRunTargetId ?? null)
|
||||||
|
const [winningRunStartAnswerCount, setWinningRunStartAnswerCount] =
|
||||||
|
useState<number | null> (storedGame?.winningRunStartAnswerCount ?? null)
|
||||||
const [activeGuessId, setActiveGuessId] = useState<number | null> (
|
const [activeGuessId, setActiveGuessId] = useState<number | null> (
|
||||||
storedGame?.activeGuessId ?? null)
|
storedGame?.activeGuessId ?? null)
|
||||||
const [reviewGuessedPostId, setReviewGuessedPostId] = useState<number | null> (
|
const [reviewGuessedPostId, setReviewGuessedPostId] = useState<number | null> (
|
||||||
@@ -979,6 +1119,8 @@ const GekanatorPage: FC = () => {
|
|||||||
rejectedPostIds: [...rejectedPostIds],
|
rejectedPostIds: [...rejectedPostIds],
|
||||||
lastGuessQuestionCount,
|
lastGuessQuestionCount,
|
||||||
lastRejectedGuessId,
|
lastRejectedGuessId,
|
||||||
|
winningRunTargetId,
|
||||||
|
winningRunStartAnswerCount,
|
||||||
activeGuessId,
|
activeGuessId,
|
||||||
reviewGuessedPostId,
|
reviewGuessedPostId,
|
||||||
reviewCorrectPostId,
|
reviewCorrectPostId,
|
||||||
@@ -1016,6 +1158,8 @@ const GekanatorPage: FC = () => {
|
|||||||
rejectedPostIds,
|
rejectedPostIds,
|
||||||
lastGuessQuestionCount,
|
lastGuessQuestionCount,
|
||||||
lastRejectedGuessId,
|
lastRejectedGuessId,
|
||||||
|
winningRunTargetId,
|
||||||
|
winningRunStartAnswerCount,
|
||||||
activeGuessId,
|
activeGuessId,
|
||||||
reviewGuessedPostId,
|
reviewGuessedPostId,
|
||||||
reviewCorrectPostId,
|
reviewCorrectPostId,
|
||||||
@@ -1053,6 +1197,20 @@ const GekanatorPage: FC = () => {
|
|||||||
const availablePosts = useMemo (
|
const availablePosts = useMemo (
|
||||||
() => posts.filter (post => !(rejectedPostIds.has (post.id))),
|
() => posts.filter (post => !(rejectedPostIds.has (post.id))),
|
||||||
[posts, rejectedPostIds])
|
[posts, rejectedPostIds])
|
||||||
|
const winningRunTargetPost = useMemo (
|
||||||
|
() => winningRunTargetId === null
|
||||||
|
? null
|
||||||
|
: posts.find (post => post.id === winningRunTargetId) ?? null,
|
||||||
|
[posts, winningRunTargetId])
|
||||||
|
const winningRunQuestionsAsked = winningRunQuestionCount (
|
||||||
|
answers,
|
||||||
|
winningRunStartAnswerCount)
|
||||||
|
const winningRunActive =
|
||||||
|
isWinningRunActive (winningRunTargetId, winningRunStartAnswerCount)
|
||||||
|
&& winningRunQuestionsAsked < winningRunQuestionLimit
|
||||||
|
&& eligiblePosts.length === 1
|
||||||
|
&& eligiblePosts[0]?.id === winningRunTargetId
|
||||||
|
&& winningRunTargetPost !== null
|
||||||
const questionPosts =
|
const questionPosts =
|
||||||
eligiblePosts.length > 1
|
eligiblePosts.length > 1
|
||||||
|| questionsSinceLastGuess >= minQuestionsBeforeCertainGuess
|
|| questionsSinceLastGuess >= minQuestionsBeforeCertainGuess
|
||||||
@@ -1064,13 +1222,23 @@ const GekanatorPage: FC = () => {
|
|||||||
.sort ((a, b) => b.score - a.score)
|
.sort ((a, b) => b.score - a.score)
|
||||||
.slice (0, 3),
|
.slice (0, 3),
|
||||||
[eligiblePosts, scores])
|
[eligiblePosts, scores])
|
||||||
const currentQuestion = chooseQuestion ({
|
const currentQuestion = winningRunActive && winningRunTargetPost
|
||||||
posts: questionPosts,
|
? chooseWinningRunQuestion ({
|
||||||
questions: scoringQuestions,
|
posts,
|
||||||
scores,
|
fallbackPosts: availablePosts.length > 1 ? availablePosts : posts,
|
||||||
answers,
|
questions: scoringQuestions,
|
||||||
askedIds,
|
targetPost: winningRunTargetPost,
|
||||||
gameSeed })
|
scores,
|
||||||
|
answers,
|
||||||
|
askedIds,
|
||||||
|
gameSeed })
|
||||||
|
: chooseQuestion ({
|
||||||
|
posts: questionPosts,
|
||||||
|
questions: scoringQuestions,
|
||||||
|
scores,
|
||||||
|
answers,
|
||||||
|
askedIds,
|
||||||
|
gameSeed })
|
||||||
const answerPreviews = useMemo (
|
const answerPreviews = useMemo (
|
||||||
() => currentQuestion
|
() => currentQuestion
|
||||||
? answerOptions.map (option => previewAnswer ({
|
? answerOptions.map (option => previewAnswer ({
|
||||||
@@ -1141,6 +1309,8 @@ const GekanatorPage: FC = () => {
|
|||||||
setRejectedPostIds (new Set ())
|
setRejectedPostIds (new Set ())
|
||||||
setLastGuessQuestionCount (0)
|
setLastGuessQuestionCount (0)
|
||||||
setLastRejectedGuessId (null)
|
setLastRejectedGuessId (null)
|
||||||
|
setWinningRunTargetId (null)
|
||||||
|
setWinningRunStartAnswerCount (null)
|
||||||
setActiveGuessId (null)
|
setActiveGuessId (null)
|
||||||
setReviewGuessedPostId (null)
|
setReviewGuessedPostId (null)
|
||||||
setReviewCorrectPostId (null)
|
setReviewCorrectPostId (null)
|
||||||
@@ -1299,6 +1469,8 @@ const GekanatorPage: FC = () => {
|
|||||||
rejectedPostIds: new Set (rejectedPostIds),
|
rejectedPostIds: new Set (rejectedPostIds),
|
||||||
lastGuessQuestionCount,
|
lastGuessQuestionCount,
|
||||||
lastRejectedGuessId,
|
lastRejectedGuessId,
|
||||||
|
winningRunTargetId,
|
||||||
|
winningRunStartAnswerCount,
|
||||||
activeGuessId,
|
activeGuessId,
|
||||||
reviewGuessedPostId,
|
reviewGuessedPostId,
|
||||||
reviewCorrectPostId }])
|
reviewCorrectPostId }])
|
||||||
@@ -1324,6 +1496,20 @@ const GekanatorPage: FC = () => {
|
|||||||
const nextRecoveredCandidatePosts = recovered.recoveredCandidatePosts
|
const nextRecoveredCandidatePosts = recovered.recoveredCandidatePosts
|
||||||
const nextScores = recovered.scores
|
const nextScores = recovered.scores
|
||||||
const nextEligiblePosts = recovered.eligiblePosts
|
const nextEligiblePosts = recovered.eligiblePosts
|
||||||
|
const currentWinningRunActive =
|
||||||
|
isWinningRunActive (winningRunTargetId, winningRunStartAnswerCount)
|
||||||
|
const nextWinningRunTargetId =
|
||||||
|
nextEligiblePosts.length === 1
|
||||||
|
? nextEligiblePosts[0]?.id ?? null
|
||||||
|
: null
|
||||||
|
const nextWinningRunStartAnswerCount =
|
||||||
|
nextWinningRunTargetId === null
|
||||||
|
? null
|
||||||
|
: currentWinningRunActive
|
||||||
|
&& winningRunTargetId === nextWinningRunTargetId
|
||||||
|
&& winningRunStartAnswerCount !== null
|
||||||
|
? winningRunStartAnswerCount
|
||||||
|
: nextAnswers.length
|
||||||
|
|
||||||
setScores (nextScores)
|
setScores (nextScores)
|
||||||
setAskedIds (nextAskedIds)
|
setAskedIds (nextAskedIds)
|
||||||
@@ -1332,6 +1518,8 @@ const GekanatorPage: FC = () => {
|
|||||||
setRecoveryStepCount (recovered.recoveryStepCount)
|
setRecoveryStepCount (recovered.recoveryStepCount)
|
||||||
setAskedQuestionBank (nextAskedQuestionBank)
|
setAskedQuestionBank (nextAskedQuestionBank)
|
||||||
setAnswers (nextAnswers)
|
setAnswers (nextAnswers)
|
||||||
|
setWinningRunTargetId (nextWinningRunTargetId)
|
||||||
|
setWinningRunStartAnswerCount (nextWinningRunStartAnswerCount)
|
||||||
|
|
||||||
const nextGuessablePosts =
|
const nextGuessablePosts =
|
||||||
nextEligiblePosts.length > 0
|
nextEligiblePosts.length > 0
|
||||||
@@ -1345,6 +1533,13 @@ const GekanatorPage: FC = () => {
|
|||||||
const topConfidence = nextConfidences[0] ?? null
|
const topConfidence = nextConfidences[0] ?? null
|
||||||
const runnerUpConfidence = nextConfidences[1] ?? null
|
const runnerUpConfidence = nextConfidences[1] ?? null
|
||||||
const structurallyCertain = nextEligiblePosts.length === 1
|
const structurallyCertain = nextEligiblePosts.length === 1
|
||||||
|
const winningRunContinues =
|
||||||
|
nextWinningRunTargetId !== null
|
||||||
|
&& nextWinningRunStartAnswerCount !== null
|
||||||
|
&& nextEligiblePosts.length === 1
|
||||||
|
&& winningRunQuestionCount (
|
||||||
|
nextAnswers,
|
||||||
|
nextWinningRunStartAnswerCount) < winningRunQuestionLimit
|
||||||
const statisticallyCertain =
|
const statisticallyCertain =
|
||||||
topConfidence !== null
|
topConfidence !== null
|
||||||
&& topConfidence.percent >= certainGuessPercent
|
&& topConfidence.percent >= certainGuessPercent
|
||||||
@@ -1357,8 +1552,9 @@ const GekanatorPage: FC = () => {
|
|||||||
&& (structurallyCertain || statisticallyCertain)
|
&& (structurallyCertain || statisticallyCertain)
|
||||||
const shouldGuess =
|
const shouldGuess =
|
||||||
nextQuestionCount >= hardMaxQuestions
|
nextQuestionCount >= hardMaxQuestions
|
||||||
|| canGuessByQuestionCount
|
|| (
|
||||||
|| canGuessEarlyByConfidence
|
!(winningRunContinues)
|
||||||
|
&& (canGuessByQuestionCount || canGuessEarlyByConfidence))
|
||||||
if (shouldGuess)
|
if (shouldGuess)
|
||||||
{
|
{
|
||||||
setActiveGuessId (nextGuess?.id ?? null)
|
setActiveGuessId (nextGuess?.id ?? null)
|
||||||
@@ -1476,6 +1672,8 @@ const GekanatorPage: FC = () => {
|
|||||||
new Map (
|
new Map (
|
||||||
[...recoveredCandidatePosts.entries ()].filter (
|
[...recoveredCandidatePosts.entries ()].filter (
|
||||||
([postId]) => postId !== displayedGuess.id)))
|
([postId]) => postId !== displayedGuess.id)))
|
||||||
|
setWinningRunTargetId (null)
|
||||||
|
setWinningRunStartAnswerCount (null)
|
||||||
setActiveGuessId (null)
|
setActiveGuessId (null)
|
||||||
setSearch ('')
|
setSearch ('')
|
||||||
setSelectingCorrectPost (false)
|
setSelectingCorrectPost (false)
|
||||||
@@ -1501,6 +1699,8 @@ const GekanatorPage: FC = () => {
|
|||||||
setRejectedPostIds (snapshot.rejectedPostIds)
|
setRejectedPostIds (snapshot.rejectedPostIds)
|
||||||
setLastGuessQuestionCount (snapshot.lastGuessQuestionCount)
|
setLastGuessQuestionCount (snapshot.lastGuessQuestionCount)
|
||||||
setLastRejectedGuessId (snapshot.lastRejectedGuessId)
|
setLastRejectedGuessId (snapshot.lastRejectedGuessId)
|
||||||
|
setWinningRunTargetId (snapshot.winningRunTargetId)
|
||||||
|
setWinningRunStartAnswerCount (snapshot.winningRunStartAnswerCount)
|
||||||
setActiveGuessId (snapshot.activeGuessId)
|
setActiveGuessId (snapshot.activeGuessId)
|
||||||
setReviewGuessedPostId (snapshot.reviewGuessedPostId)
|
setReviewGuessedPostId (snapshot.reviewGuessedPostId)
|
||||||
setReviewCorrectPostId (snapshot.reviewCorrectPostId)
|
setReviewCorrectPostId (snapshot.reviewCorrectPostId)
|
||||||
@@ -1525,20 +1725,54 @@ const GekanatorPage: FC = () => {
|
|||||||
setRecoveredCandidatePosts (recovered.recoveredCandidatePosts)
|
setRecoveredCandidatePosts (recovered.recoveredCandidatePosts)
|
||||||
setRecoveryStepCount (recovered.recoveryStepCount)
|
setRecoveryStepCount (recovered.recoveryStepCount)
|
||||||
setScores (recovered.scores)
|
setScores (recovered.scores)
|
||||||
|
const nextWinningRunTargetId =
|
||||||
|
recovered.eligiblePosts.length === 1
|
||||||
|
? recovered.eligiblePosts[0]?.id ?? null
|
||||||
|
: null
|
||||||
|
const nextWinningRunStartAnswerCount =
|
||||||
|
nextWinningRunTargetId === null
|
||||||
|
? null
|
||||||
|
: isWinningRunActive (winningRunTargetId, winningRunStartAnswerCount)
|
||||||
|
&& winningRunTargetId === nextWinningRunTargetId
|
||||||
|
&& winningRunStartAnswerCount !== null
|
||||||
|
? winningRunStartAnswerCount
|
||||||
|
: answers.length
|
||||||
|
const nextWinningRunTargetPost =
|
||||||
|
nextWinningRunTargetId === null
|
||||||
|
? null
|
||||||
|
: posts.find (post => post.id === nextWinningRunTargetId) ?? null
|
||||||
|
|
||||||
const recoveredGuessablePosts =
|
const recoveredGuessablePosts =
|
||||||
recovered.eligiblePosts.length > 0
|
recovered.eligiblePosts.length > 0
|
||||||
? recovered.eligiblePosts
|
? recovered.eligiblePosts
|
||||||
: availablePosts
|
: availablePosts
|
||||||
const nextQuestion = chooseQuestion ({
|
const nextQuestion =
|
||||||
posts: recovered.eligiblePosts.length > 1
|
nextWinningRunTargetPost
|
||||||
? recovered.eligiblePosts
|
&& nextWinningRunStartAnswerCount !== null
|
||||||
: availablePosts,
|
&& winningRunQuestionCount (
|
||||||
questions: recovered.scoringQuestions,
|
answers,
|
||||||
scores: recovered.scores,
|
nextWinningRunStartAnswerCount) < winningRunQuestionLimit
|
||||||
answers,
|
? chooseWinningRunQuestion ({
|
||||||
askedIds,
|
posts,
|
||||||
gameSeed })
|
fallbackPosts: availablePosts.length > 1 ? availablePosts : posts,
|
||||||
|
questions: recovered.scoringQuestions,
|
||||||
|
targetPost: nextWinningRunTargetPost,
|
||||||
|
scores: recovered.scores,
|
||||||
|
answers,
|
||||||
|
askedIds,
|
||||||
|
gameSeed })
|
||||||
|
: chooseQuestion ({
|
||||||
|
posts: recovered.eligiblePosts.length > 1
|
||||||
|
? recovered.eligiblePosts
|
||||||
|
: availablePosts,
|
||||||
|
questions: recovered.scoringQuestions,
|
||||||
|
scores: recovered.scores,
|
||||||
|
answers,
|
||||||
|
askedIds,
|
||||||
|
gameSeed })
|
||||||
|
|
||||||
|
setWinningRunTargetId (nextWinningRunTargetId)
|
||||||
|
setWinningRunStartAnswerCount (nextWinningRunStartAnswerCount)
|
||||||
|
|
||||||
if (nextQuestion)
|
if (nextQuestion)
|
||||||
{
|
{
|
||||||
@@ -1661,6 +1895,39 @@ const GekanatorPage: FC = () => {
|
|||||||
&& !(error)
|
&& !(error)
|
||||||
&& !(acceptedQuestionsError)
|
&& !(acceptedQuestionsError)
|
||||||
|
|
||||||
|
useEffect (() => {
|
||||||
|
if (
|
||||||
|
phase !== 'question'
|
||||||
|
|| isLoading
|
||||||
|
|| acceptedQuestionsLoading
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
const winningRunFinished =
|
||||||
|
winningRunTargetId !== null
|
||||||
|
&& winningRunStartAnswerCount !== null
|
||||||
|
&& winningRunQuestionCount (answers, winningRunStartAnswerCount) >= winningRunQuestionLimit
|
||||||
|
&& eligiblePosts.length === 1
|
||||||
|
&& eligiblePosts[0]?.id === winningRunTargetId
|
||||||
|
const nextGuess = displayedGuess ?? guess
|
||||||
|
if (currentQuestion || (!(winningRunFinished) && !(nextGuess)))
|
||||||
|
return
|
||||||
|
|
||||||
|
setActiveGuessId ((winningRunFinished ? guess : nextGuess)?.id ?? null)
|
||||||
|
setLastGuessQuestionCount (answers.length)
|
||||||
|
setPhase ('guess')
|
||||||
|
}, [
|
||||||
|
phase,
|
||||||
|
currentQuestion,
|
||||||
|
guess,
|
||||||
|
displayedGuess,
|
||||||
|
answers,
|
||||||
|
eligiblePosts,
|
||||||
|
winningRunTargetId,
|
||||||
|
winningRunStartAnswerCount,
|
||||||
|
isLoading,
|
||||||
|
acceptedQuestionsLoading])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MainArea className="bg-yellow-50 dark:bg-red-975">
|
<MainArea className="bg-yellow-50 dark:bg-red-975">
|
||||||
<Helmet>
|
<Helmet>
|
||||||
@@ -1767,24 +2034,6 @@ const GekanatorPage: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>)}
|
</div>)}
|
||||||
|
|
||||||
{!(isLoading) && phase === 'question' && !(currentQuestion) && (
|
|
||||||
<div className="space-y-4">
|
|
||||||
<p className="text-xl font-bold">
|
|
||||||
もう十分わかった。
|
|
||||||
</p>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="rounded border border-yellow-300 px-4 py-2
|
|
||||||
hover:bg-yellow-100 dark:border-red-700
|
|
||||||
dark:hover:bg-red-900"
|
|
||||||
onClick={() => {
|
|
||||||
setActiveGuessId (guess?.id ?? null)
|
|
||||||
setPhase ('guess')
|
|
||||||
}}>
|
|
||||||
答える
|
|
||||||
</button>
|
|
||||||
</div>)}
|
|
||||||
|
|
||||||
{phase === 'guess' && displayedGuess && (
|
{phase === 'guess' && displayedGuess && (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<p className="text-xl font-bold">これを想像してゐたね?</p>
|
<p className="text-xl font-bold">これを想像してゐたね?</p>
|
||||||
|
|||||||
新しい課題から参照
ユーザをブロックする