このコミットが含まれているのは:
2026-06-25 08:11:41 +09:00
コミット c10ba7a698
36個のファイルの変更886行の追加1132行の削除
+73 -146
ファイルの表示
@@ -238,8 +238,7 @@ const createGameSeed = (): string => {
const normalizeStoredQuestionId = (
questionId: string,
condition?: GekanatorQuestionCondition,
): string => {
condition?: GekanatorQuestionCondition): string => {
if (condition?.type === 'title-length-greater-than')
return `title:length-at-least:${ condition.length + 1 }`
@@ -312,8 +311,7 @@ const sourcePriorityForMerge = (question: GekanatorQuestion): number => {
const shouldReplaceMergedQuestion = (
current: GekanatorQuestion | undefined,
candidate: GekanatorQuestion,
): boolean => {
candidate: GekanatorQuestion): boolean => {
if (!(current))
return true
@@ -408,8 +406,7 @@ const loadRecentGames = (): RecentGameSummary[] => {
const storeRecentGameSummary = (
summary: RecentGameSummary,
): RecentGameSummary[] => {
summary: RecentGameSummary): RecentGameSummary[] => {
const next =
[summary,
...loadRecentGames ().filter (item => (item.savedAt !== summary.savedAt
@@ -459,8 +456,7 @@ const resettableExtraQuestionState = (): {
const recoveredCandidateMapFromStored = (
items: RecoveredCandidatePost[],
scores: [number, number][],
): Map<number, RecoveredCandidateState> => {
scores: [number, number][]): Map<number, RecoveredCandidateState> => {
const storedScores = new Map (scores)
return new Map (items.map (item => [item.postId, {
@@ -470,8 +466,7 @@ const recoveredCandidateMapFromStored = (
const storedRecoveredCandidatesFromMap = (
recoveredCandidatePosts: Map<number, RecoveredCandidateState>,
): RecoveredCandidatePost[] =>
recoveredCandidatePosts: Map<number, RecoveredCandidateState>): RecoveredCandidatePost[] =>
[...recoveredCandidatePosts.entries ()]
.map (([postId, recoveredCandidate]) => ({
postId,
@@ -513,8 +508,7 @@ const distributionEntropy = (weights: number[]): number =>
const questionCategoryPenalty = (
question: GekanatorQuestion,
answerCount: number,
repeatPenalty: number,
): number => {
repeatPenalty: number): number => {
const earlyFactor = Math.max (0, (3 - answerCount) / 3)
const titleLengthPenalty = (() => {
if (titleLengthMinimumForCondition (question.condition) == null)
@@ -553,8 +547,7 @@ const relatedPostIdsOf = (post: Post): number[] => {
const userPriorWeightsFor = (
posts: Post[],
recentGames: RecentGameSummary[],
): Map<number, number> => {
recentGames: RecentGameSummary[]): Map<number, number> => {
const postById = new Map (posts.map (post => [post.id, post]))
const weights = new Map<number, number> ()
const addWeight = (postId: number, weight: number) => {
@@ -581,14 +574,12 @@ const userPriorWeightsFor = (
const answerWeightFor = (
questionId: string,
softenedQuestionIds: Set<string>,
): number => softenedQuestionIds.has (questionId) ? softenedAnswerWeight : 1
softenedQuestionIds: Set<string>): number => softenedQuestionIds.has (questionId) ? softenedAnswerWeight : 1
const scoreWeightForAnswer = (
answer: GekanatorAnswerLog,
softenedQuestionIds: Set<string>,
): number =>
softenedQuestionIds: Set<string>): number =>
answerWeightFor (answer.questionId, softenedQuestionIds)
* (
answer.questionPurpose === 'learning_user_suggested'
@@ -638,8 +629,7 @@ const titleTermPattern =
const addPostIdToIndex = <K extends string | number> (
index: Map<K, Set<number>>,
key: K,
postId: number,
) => {
postId: number) => {
const current = index.get (key)
if (current)
{
@@ -652,8 +642,7 @@ const addPostIdToIndex = <K extends string | number> (
const buildMaterialIndex = (
posts: Post[],
): GekanatorQuestionMaterialIndex => {
posts: Post[]): GekanatorQuestionMaterialIndex => {
const postById = new Map<number, Post> ()
const tagKeysByPostId = new Map<number, string[]> ()
const postIdsByTagKey = new Map<string, Set<number>> ()
@@ -784,8 +773,7 @@ const originalDateQuestionTextFor = (
condition: Extract<
GekanatorQuestionCondition,
{ type: 'original-year' | 'original-month' | 'original-month-day' }
>,
): string => {
>): string => {
switch (condition.type)
{
case 'original-year':
@@ -852,8 +840,7 @@ const isLearnableTagKey = (key: string): boolean => !(key.startsWith ('nico:'))
const isUserSuggestedLearnedSemanticQuestion = (
question: GekanatorQuestion,
): boolean => isLearnedSemanticQuestion (question)
question: GekanatorQuestion): boolean => isLearnedSemanticQuestion (question)
type LearnedSemanticCandidateStats = {
@@ -872,8 +859,7 @@ const learnedSemanticStatsForCandidateIds = (
question }: {
candidateIds: number[]
posts: Post[]
question: GekanatorQuestion },
): LearnedSemanticCandidateStats => {
question: GekanatorQuestion }): LearnedSemanticCandidateStats => {
const candidateIdSet = new Set (candidateIds)
const positiveIds = new Set<number> ()
const negativeIds = new Set<number> ()
@@ -915,8 +901,7 @@ const learnedSemanticQuestionIsEffectiveForCandidateIds = (
question }: {
candidateIds: number[]
posts: Post[]
question: GekanatorQuestion },
): boolean => {
question: GekanatorQuestion }): boolean => {
if (!(isUserSuggestedLearnedSemanticQuestion (question)))
return false
@@ -936,8 +921,7 @@ const learnedSemanticQuestionIsEffectiveForCandidateIds = (
const directSemanticAnswerForPost = (
question: GekanatorQuestion,
post: Post,
): GekanatorAnswerValue | null => {
post: Post): GekanatorAnswerValue | null => {
const direct = question.exampleAnswers?.[String (post.id) as `${ number }`]
if (direct)
return direct
@@ -956,8 +940,7 @@ const learnedSemanticLearningValueForTopPosts = (
question: GekanatorQuestion
learningTargetPosts: Post[]
candidateIds: number[]
posts: Post[] },
): { missingTopCount: number
posts: Post[] }): { missingTopCount: number
knownCount: number
hasLearningValue: boolean } => {
const missingTopCount =
@@ -1000,8 +983,7 @@ const learningTargetPostsForCandidates = ({
const questionPurposeCountsFor = (
answers: GekanatorAnswerLog[],
): {
answers: GekanatorAnswerLog[]): {
effectiveUserSuggestedCount: number
learningUserSuggestedCount: number
normalQuestionCount: number
@@ -1041,8 +1023,7 @@ const questionPurposeCountsFor = (
const learnedSemanticNarrowPenaltyForStats = (
candidateCount: number,
stats: LearnedSemanticCandidateStats,
): number => {
stats: LearnedSemanticCandidateStats): number => {
const minSide = candidateCount < 10 ? 1 : Math.max (3, candidateCount * .08)
return stats.positiveCount < minSide || stats.negativeCount < minSide ? .15 : 0
}
@@ -1050,8 +1031,7 @@ const learnedSemanticNarrowPenaltyForStats = (
const learnedSemanticScoreDeltaForExpectedAnswer = (
userAnswer: GekanatorAnswerValue,
expectedAnswer: GekanatorAnswerValue | null,
): number => {
expectedAnswer: GekanatorAnswerValue | null): number => {
switch (userAnswer)
{
case 'yes':
@@ -1089,8 +1069,7 @@ const learnedSemanticScoreDeltaForExpectedAnswer = (
const scoreDropDeltaForRecoveredPost = (
postId: number,
totalScore: number,
recoveredCandidatePosts: Map<number, RecoveredCandidateState>,
): number => {
recoveredCandidatePosts: Map<number, RecoveredCandidateState>): number => {
const recoveredCandidate = recoveredCandidatePosts.get (postId)
if (recoveredCandidate == null)
return totalScore
@@ -1114,8 +1093,7 @@ const postPassesScoreDrop = (
recoveredCandidatePosts }: {
postId: number
scores: Map<number, number>
recoveredCandidatePosts: Map<number, RecoveredCandidateState> },
): boolean => {
recoveredCandidatePosts: Map<number, RecoveredCandidateState> }): boolean => {
if (!(activeCandidateScoreDropEnabled (scores)))
return true
@@ -1129,8 +1107,7 @@ const postPassesScoreDrop = (
// `post_similarities` is the score-propagation graph, not the question kind.
const questionUsesPostSimilarityPropagationGraphForScoring = (
question: GekanatorQuestion,
): boolean =>
question: GekanatorQuestion): boolean =>
(question.kind === 'post_similarity'
&& !(isUserSuggestedLearnedSemanticQuestion (question)))
|| (question.kind === 'tag'
@@ -1139,8 +1116,7 @@ const questionUsesPostSimilarityPropagationGraphForScoring = (
const questionSupportsAnswerBasedHardFiltering = (
question: GekanatorQuestion,
): boolean => !(questionUsesPostSimilarityPropagationGraphForScoring (question))
question: GekanatorQuestion): boolean => !(questionUsesPostSimilarityPropagationGraphForScoring (question))
&& !(isUserSuggestedLearnedSemanticQuestion (question))
@@ -1160,8 +1136,7 @@ const usesLearnedTagExamples = (question: GekanatorQuestion): boolean =>
const searchedQuestionsFor = (
questions: GekanatorQuestion[],
search: string,
): GekanatorQuestion[] => {
search: string): GekanatorQuestion[] => {
const needle = search.trim ()
if (!(needle))
return []
@@ -1235,8 +1210,7 @@ type QuestionMatchResolver = {
const buildGekanatorMatchIndex = (
posts: Post[],
questions: GekanatorQuestion[],
): GekanatorMatchIndex => new Map (
questions: GekanatorQuestion[]): GekanatorMatchIndex => new Map (
questions.map (question => [
question.id,
new Set (
@@ -1285,8 +1259,7 @@ const matchingPostIdsForQuestion = ({
const positiveMatchingPostIdsForQuestion = (
resolver: QuestionMatchResolver,
): Set<number> => {
resolver: QuestionMatchResolver): Set<number> => {
if (isUserSuggestedLearnedSemanticQuestion (resolver.question))
{
const cached = resolver.dynamicMatchIndex?.get (resolver.question.id)
@@ -1356,8 +1329,7 @@ const matchingWeightInCandidates = (
materialIndex: GekanatorQuestionMaterialIndex
matchIndex: GekanatorMatchIndex
question: GekanatorQuestion
dynamicMatchIndex?: GekanatorMatchIndex },
): number => {
dynamicMatchIndex?: GekanatorMatchIndex }): number => {
const matched = positiveMatchingPostIdsForQuestion ({
posts,
materialIndex,
@@ -1380,8 +1352,7 @@ const signatureForCandidateIds = (
materialIndex: GekanatorQuestionMaterialIndex
matchIndex: GekanatorMatchIndex
question: GekanatorQuestion
dynamicMatchIndex?: GekanatorMatchIndex },
): string => {
dynamicMatchIndex?: GekanatorMatchIndex }): string => {
if (isUserSuggestedLearnedSemanticQuestion (question))
{
const postById = new Map (posts.map (post => [post.id, post]))
@@ -1421,8 +1392,7 @@ const postIdsForHardAnswer = (
posts: Post[]
materialIndex: GekanatorQuestionMaterialIndex
matchIndex: GekanatorMatchIndex
dynamicMatchIndex?: GekanatorMatchIndex },
): number[] => {
dynamicMatchIndex?: GekanatorMatchIndex }): number[] => {
if (!(questionSupportsAnswerBasedHardFiltering (question)))
return candidateIds
@@ -1562,8 +1532,7 @@ const buildIndexedQuestion = (
text: string
kind: GekanatorQuestionKind
priorityWeight: number
materialIndex: GekanatorQuestionMaterialIndex },
): GekanatorQuestion => ({
materialIndex: GekanatorQuestionMaterialIndex }): GekanatorQuestion => ({
id: questionIdForCondition (condition),
text,
kind,
@@ -1578,8 +1547,7 @@ const buildIndexedQuestion = (
const rankedEntriesForCounts = <T extends string | number> (
{ counts, total, cap }: { counts: Map<T, number>
total: number
cap: number },
): [T, number][] =>
cap: number }): [T, number][] =>
([...counts.entries ()]
.filter (([, count]) => count > 0 && count < total)
.sort ((a, b) => Math.abs (total / 2 - a[1]) - Math.abs (total / 2 - b[1]))
@@ -1594,8 +1562,7 @@ const buildQuestionsForCandidateIds = (
materialIndex: GekanatorQuestionMaterialIndex
acceptedQuestions: GekanatorQuestion[]
mode?: QuestionBuildMode
confirmationPostId?: number | null },
): GekanatorQuestion[] => {
confirmationPostId?: number | null }): GekanatorQuestion[] => {
const total = candidateIds.length
const confirmationPost = (() => {
if (confirmationPostId == null)
@@ -1652,8 +1619,7 @@ const buildQuestionsForCandidateIds = (
condition: Extract<
GekanatorQuestionCondition,
{ type: 'original-year' | 'original-month' | 'original-month-day' }
>,
): GekanatorQuestion => {
>): GekanatorQuestion => {
const priorityWeight = (() => {
if (condition.type === 'original-year')
return 1.04
@@ -1673,8 +1639,7 @@ const buildQuestionsForCandidateIds = (
const specialMonthDays = rankedEntriesForCounts ({
counts: monthDayCounts,
total,
cap: factCap
}).filter (([monthDay]) => specialOriginalMonthDayLabelFor (String (monthDay)) != null)
cap: factCap}).filter (([monthDay]) => specialOriginalMonthDayLabelFor (String (monthDay)) != null)
if (mode === 'split')
{
@@ -2124,8 +2089,7 @@ type ExclusiveConditionGroup =
const exclusiveConditionGroupFor = (
condition: GekanatorQuestion['condition'],
): ExclusiveConditionGroup | null => {
condition: GekanatorQuestion['condition']): ExclusiveConditionGroup | null => {
switch (condition.type)
{
case 'original-month':
@@ -2144,8 +2108,7 @@ const exclusiveConditionGroupFor = (
const sameConditionValue = (
left: GekanatorQuestion['condition'],
right: GekanatorQuestion['condition'],
): boolean => {
right: GekanatorQuestion['condition']): boolean => {
const leftTitleLength = titleLengthMinimumForCondition (left)
const rightTitleLength = titleLengthMinimumForCondition (right)
if (leftTitleLength != null || rightTitleLength != null)
@@ -2187,8 +2150,7 @@ const sameConditionValue = (
const isMonthCrossMatch = (
candidate: GekanatorQuestion['condition'],
previous: GekanatorQuestion['condition'],
): boolean => {
previous: GekanatorQuestion['condition']): boolean => {
const candidateMonth = monthForCondition (candidate)
const previousMonth = monthForCondition (previous)
if (candidateMonth == null || previousMonth == null)
@@ -2204,8 +2166,7 @@ const isMonthCrossMatch = (
const isExclusiveContradiction = (
candidate: GekanatorQuestion['condition'],
previous: GekanatorQuestion['condition'],
): boolean => {
previous: GekanatorQuestion['condition']): boolean => {
const candidateGroup = exclusiveConditionGroupFor (candidate)
const previousGroup = exclusiveConditionGroupFor (previous)
@@ -2242,16 +2203,14 @@ const contradictionPenaltyFor = ({
case 'no':
if (
sameConditionValue (question.condition, previous)
|| isMonthCrossMatch (question.condition, previous)
)
|| isMonthCrossMatch (question.condition, previous))
return sum + 40
return sum
case 'probably_no':
if (
sameConditionValue (question.condition, previous)
|| isMonthCrossMatch (question.condition, previous)
)
|| isMonthCrossMatch (question.condition, previous))
return sum + 20
return sum
@@ -2281,8 +2240,7 @@ const chooseQuestion = (
recentFirstQuestionPenaltyById: Map<string, number>
userPriorWeights: Map<number, number>
materialIndex: GekanatorQuestionMaterialIndex
matchIndex: GekanatorMatchIndex },
): QuestionSelection | null => {
matchIndex: GekanatorMatchIndex }): QuestionSelection | null => {
const dynamicMatchIndex = new Map<string, Set<number>> ()
const invertedSignature = (signature: string): string =>
@@ -2327,8 +2285,7 @@ const chooseQuestion = (
const rank = (
questionsToRank: GekanatorQuestion[],
candidates: { post: Post; score: number }[],
weightedCandidates: { post: Post; score: number; weight: number }[],
) => {
weightedCandidates: { post: Post; score: number; weight: number }[]) => {
const redundant = redundantSignatures (candidates.map (item => item.post))
const candidateById = new Map (candidates.map (item => [item.post.id, item.post]))
const candidateIds = candidates.map (item => item.post.id)
@@ -2613,8 +2570,7 @@ const chooseQuestion = (
if (
effectiveRatio < targetEffectiveUserSuggestedQuestionRatio
&& totalUserSuggestedRatio < targetTotalUserSuggestedQuestionRatio
&& effectiveUserSuggestedPool.length > 0
)
&& effectiveUserSuggestedPool.length > 0)
{
selectedPool = effectiveUserSuggestedPool
selectedPurpose = 'effective_user_suggested'
@@ -2622,8 +2578,7 @@ const chooseQuestion = (
else if (
learningRatio < targetLearningUserSuggestedQuestionRatio
&& totalUserSuggestedRatio < targetTotalUserSuggestedQuestionRatio
&& learningUserSuggestedPool.length > 0
)
&& learningUserSuggestedPool.length > 0)
{
selectedPool = learningUserSuggestedPool
selectedPurpose = 'learning_user_suggested'
@@ -2683,8 +2638,7 @@ const chooseQuestion = (
const winningRunPriorityFor = (
expected: GekanatorAnswerValue,
): number | null => {
expected: GekanatorAnswerValue): number | null => {
if (expected === 'yes')
return 0
if (expected === 'partial')
@@ -2719,8 +2673,7 @@ const chooseWinningRunQuestion = ({
materialIndex,
acceptedQuestions,
mode: 'confirmation',
confirmationPostId: targetPost.id
})
confirmationPostId: targetPost.id})
.filter (question => {
if (askedIds.has (question.id))
return false
@@ -2829,8 +2782,7 @@ const chooseFallbackQuestion = ({
materialIndex,
acceptedQuestions: [],
mode: 'confirmation',
confirmationPostId: post.id
})))
confirmationPostId: post.id})))
.slice (0, 32)
const dynamicMatchIndex = new Map<string, Set<number>> ()
const ranked = mergeQuestions ([
@@ -2905,8 +2857,7 @@ const chooseFallbackQuestion = ({
const shouldEnterGuessPhase = (
reason: GuessReason | null,
): reason is 'hard_max_questions' | 'winning_run_finished' | 'question_count_checkpoint' =>
reason: GuessReason | null): reason is 'hard_max_questions' | 'winning_run_finished' | 'question_count_checkpoint' =>
(reason === 'hard_max_questions'
|| reason === 'winning_run_finished'
|| reason === 'question_count_checkpoint')
@@ -2914,15 +2865,13 @@ const shouldEnterGuessPhase = (
const isWinningRunActive = (
winningRunTargetId: number | null,
winningRunStartAnswerCount: number | null,
): boolean =>
winningRunStartAnswerCount: number | null): boolean =>
winningRunTargetId != null && winningRunStartAnswerCount != null
const winningRunQuestionCount = (
answers: GekanatorAnswerLog[],
winningRunStartAnswerCount: number | null,
): number => {
winningRunStartAnswerCount: number | null): number => {
if (winningRunStartAnswerCount == null)
return 0
@@ -2962,8 +2911,7 @@ const nextQuestionPlanFor = (
matchIndex: GekanatorMatchIndex
lastGuessQuestionCount: number
winningRunTargetId: number | null
winningRunStartAnswerCount: number | null },
): { question: GekanatorQuestion | null
winningRunStartAnswerCount: number | null }): { question: GekanatorQuestion | null
guess: Post | null
guessReason: GuessReason | null
questionMode: QuestionMode
@@ -3013,8 +2961,7 @@ const nextQuestionPlanFor = (
if (
isWinningRunActive (winningRunTargetId, winningRunStartAnswerCount)
&& winningRunTargetId === nextWinningRunTargetId
&& winningRunStartAnswerCount != null
)
&& winningRunStartAnswerCount != null)
return winningRunStartAnswerCount
return answers.length
@@ -3188,8 +3135,7 @@ const mascotStateFor = (
resultWon: boolean | null,
eligiblePostCount: number,
bestConfidencePercent: number,
winningRunActive: boolean,
): MascotState => {
winningRunActive: boolean): MascotState => {
const resultPhase =
phase === 'end'
|| phase === 'review'
@@ -3210,13 +3156,11 @@ const mascotStateFor = (
if (
winningRunActive
|| eligiblePostCount <= 2
|| bestConfidencePercent >= 70
)
|| bestConfidencePercent >= 70)
return 'thinking_near'
if (
eligiblePostCount >= 15
&& bestConfidencePercent < 45
)
&& bestConfidencePercent < 45)
return 'thinking_far'
return 'thinking_mid'
case 'guess':
@@ -3327,8 +3271,7 @@ const GekanatorBackdrop: FC<{
const settingsForMode = useCallback (
(
mode: 'normal' | 'winning_run' | 'guess',
): { columns: number; rows: number; opacity: number } => {
mode: 'normal' | 'winning_run' | 'guess'): { columns: number; rows: number; opacity: number } => {
if (mode === 'winning_run' || mode === 'guess')
return { columns: 8, rows: 8, opacity: motionMode === 'calm' ? .18 : .24 }
@@ -3342,8 +3285,7 @@ const GekanatorBackdrop: FC<{
const scaleForMode = useCallback (
(
mode: 'normal' | 'winning_run' | 'guess',
displayedWinningCount: number,
): number => {
displayedWinningCount: number): number => {
if (mode === 'guess')
return 8
@@ -3355,8 +3297,7 @@ const GekanatorBackdrop: FC<{
[])
const postsForMode = useCallback ((
mode: 'normal' | 'winning_run' | 'guess',
): Post[] => {
mode: 'normal' | 'winning_run' | 'guess'): Post[] => {
if (mode === 'guess' && displayedGuess)
return [displayedGuess]
if (mode === 'winning_run' && winningRunTargetPost)
@@ -3366,8 +3307,7 @@ const GekanatorBackdrop: FC<{
const thumbnailsForMode = useCallback ((
mode: 'normal' | 'winning_run' | 'guess',
count: number,
): string[] => {
count: number): string[] => {
const modePosts = postsForMode (mode)
if (modePosts.length === 0)
return []
@@ -3734,8 +3674,7 @@ const GekanatorBackdrop: FC<{
const expectedAnswerFor = (
question: GekanatorQuestion | undefined,
correctPost: Post | null,
): GekanatorAnswerValue | null =>
correctPost: Post | null): GekanatorAnswerValue | null =>
expectedAnswerForQuestion (question, correctPost)
@@ -4169,8 +4108,7 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
setSaved (true)
setSavedGameId (data.id)
setLearnedExampleCount (data.learnedExampleCount)
setResultWon (variables.guessedPostId === variables.correctPostId)
}})
setResultWon (variables.guessedPostId === variables.correctPostId)}})
const questionSuggestionMutation = useMutation ({
mutationFn: saveGekanatorQuestionSuggestion,
onSuccess: async data => {
@@ -4180,15 +4118,13 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
setQuestionSuggestionSearch ('')
setQuestionSuggestionSelectedId (null)
setQuestionSuggestion ('')
setQuestionSuggestionAnswer ('yes')
}})
setQuestionSuggestionAnswer ('yes')}})
const extraQuestionAnswersMutation = useMutation ({
mutationFn: saveGekanatorExtraQuestionAnswers,
onSuccess: async () => {
await queryClient.refetchQueries ({ queryKey: gekanatorKeys.questions () })
setExtraQuestionState ('saved')
setPhase ('end')
}})
setPhase ('end')}})
const resetExtraQuestionState = () => {
const next = resettableExtraQuestionState ()
@@ -4330,8 +4266,7 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
if (
!(allowPreQuestionRecovery)
|| recoveredEligiblePosts.length === 0
|| recoveredEligiblePosts.length === 1
)
|| recoveredEligiblePosts.length === 1)
return false
const nextQuestion = chooseQuestion ({
@@ -4493,8 +4428,7 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
if (
!(nextPlan.question)
&& !(shouldEnterGuessPhase (nextPlan.guessReason))
&& recovered.eligiblePosts.length !== 1
)
&& recovered.eligiblePosts.length !== 1)
{
const recoveredForQuestion = recoverQuestionState ({
nextAnswers,
@@ -4602,8 +4536,7 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
!(canPersistGame)
|| reviewGuessedPostId == null
|| reviewCorrectPostId == null
|| saveMutation.isPending
)
|| saveMutation.isPending)
return
if (savedGameId != null)
@@ -4666,8 +4599,7 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
!(canPersistGame)
|| savedGameId == null
|| extraQuestionAnswersMutation.isPending
|| extraQuestions.some (question => !(extraQuestionAnswers[String (question.id)]))
)
|| extraQuestions.some (question => !(extraQuestionAnswers[String (question.id)])))
return
extraQuestionAnswersMutation.mutate ({
@@ -4870,8 +4802,7 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
const answerExtraQuestion = (
questionId: number,
value: GekanatorAnswerValue,
) => {
value: GekanatorAnswerValue) => {
setExtraQuestionAnswers ({
...extraQuestionAnswers,
[String (questionId)]: value })
@@ -4909,8 +4840,7 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
|| isLoading
|| acceptedQuestionsLoading
|| shouldEnterGuessPhase (questionPlan.guessReason)
|| eligiblePosts.length === 1
)
|| eligiblePosts.length === 1)
return
const recovered = recoverQuestionState ({
@@ -4926,8 +4856,7 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
if (
recovered.recoveryStepCount === recoveryStepCount
&& recovered.recoveredCandidatePosts.size === recoveredCandidatePosts.size
&& recovered.softenedQuestionIds.size === softenedQuestionIds.size
)
&& recovered.softenedQuestionIds.size === softenedQuestionIds.size)
return
setSoftenedQuestionIds (recovered.softenedQuestionIds)
@@ -4954,15 +4883,13 @@ const GekanatorPage: FC<{ user: User | null }> = ({ user }) => {
if (
phase !== 'question'
|| isLoading
|| acceptedQuestionsLoading
)
|| acceptedQuestionsLoading)
return
if (
currentQuestion
|| !(questionPlan.guess)
|| !(shouldEnterGuessPhase (questionPlan.guessReason))
)
|| !(shouldEnterGuessPhase (questionPlan.guessReason)))
return
setWinningRunTargetId (questionPlan.winningRunTargetId)