Reviewed-on: #364 Co-authored-by: miteruzo <miteruzo@naver.com> Co-committed-by: miteruzo <miteruzo@naver.com>
このコミットはPull リクエスト #364 でマージされました.
このコミットが含まれているのは:
@@ -10,11 +10,13 @@ import { buildGekanatorQuestions,
|
||||
fetchGekanatorExtraQuestions,
|
||||
fetchGekanatorQuestions,
|
||||
fetchGekanatorPosts,
|
||||
normalizeTitleLengthCondition,
|
||||
restoreGekanatorQuestion,
|
||||
saveGekanatorExtraQuestionAnswers,
|
||||
saveGekanatorGame,
|
||||
saveGekanatorQuestionSuggestion,
|
||||
storeGekanatorQuestion } from '@/lib/gekanator'
|
||||
storeGekanatorQuestion,
|
||||
titleLengthMinimumForCondition } from '@/lib/gekanator'
|
||||
import { gekanatorKeys } from '@/lib/queryKeys'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
@@ -23,6 +25,7 @@ import type { FC } from 'react'
|
||||
import type { GekanatorAnswerLog,
|
||||
GekanatorAnswerValue,
|
||||
GekanatorExtraQuestion,
|
||||
GekanatorQuestionCondition,
|
||||
GekanatorQuestion,
|
||||
StoredGekanatorQuestion } from '@/lib/gekanator'
|
||||
import type { Post } from '@/types'
|
||||
@@ -144,6 +147,46 @@ const createGameSeed = (): string => {
|
||||
}
|
||||
|
||||
|
||||
const normalizeStoredQuestionId = (
|
||||
questionId: string,
|
||||
condition?: GekanatorQuestionCondition,
|
||||
): string => {
|
||||
if (condition?.type === 'title-length-greater-than')
|
||||
return `title:length-at-least:${ condition.length + 1 }`
|
||||
|
||||
if (questionId.startsWith ('title:length-greater-than:'))
|
||||
{
|
||||
const length = Number (questionId.split (':').pop ())
|
||||
if (Number.isInteger (length))
|
||||
return `title:length-at-least:${ length + 1 }`
|
||||
}
|
||||
|
||||
return questionId
|
||||
}
|
||||
|
||||
|
||||
const normalizeStoredGame = (game: StoredGekanatorGame): StoredGekanatorGame => ({
|
||||
...game,
|
||||
answers: game.answers.map (answer => ({
|
||||
...answer,
|
||||
questionId: normalizeStoredQuestionId (
|
||||
answer.questionId,
|
||||
answer.questionCondition),
|
||||
questionCondition: answer.questionCondition
|
||||
? normalizeTitleLengthCondition (answer.questionCondition)
|
||||
: undefined })),
|
||||
askedIds: game.askedIds.map (questionId => normalizeStoredQuestionId (questionId)),
|
||||
softenedQuestionIds: game.softenedQuestionIds.map (questionId =>
|
||||
normalizeStoredQuestionId (questionId)),
|
||||
askedQuestionBank: game.askedQuestionBank?.map (question =>
|
||||
({
|
||||
...question,
|
||||
id: normalizeStoredQuestionId (question.id, question.condition),
|
||||
condition: normalizeTitleLengthCondition (question.condition) })),
|
||||
askedQuestionBankIds: game.askedQuestionBankIds?.map (questionId =>
|
||||
normalizeStoredQuestionId (questionId)) })
|
||||
|
||||
|
||||
const sourcePriorityForMerge = (question: GekanatorQuestion): number => {
|
||||
switch (question.source)
|
||||
{
|
||||
@@ -214,7 +257,7 @@ const loadStoredGame = (): StoredGekanatorGame | null => {
|
||||
if (!(raw))
|
||||
return null
|
||||
|
||||
return JSON.parse (raw) as StoredGekanatorGame
|
||||
return normalizeStoredGame (JSON.parse (raw) as StoredGekanatorGame)
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -548,6 +591,13 @@ const sameConditionValue = (
|
||||
left: GekanatorQuestion['condition'],
|
||||
right: GekanatorQuestion['condition'],
|
||||
): boolean => {
|
||||
const leftTitleLength = titleLengthMinimumForCondition (left)
|
||||
const rightTitleLength = titleLengthMinimumForCondition (right)
|
||||
if (leftTitleLength !== null || rightTitleLength !== null)
|
||||
return leftTitleLength !== null
|
||||
&& rightTitleLength !== null
|
||||
&& leftTitleLength === rightTitleLength
|
||||
|
||||
if (left.type !== right.type)
|
||||
return false
|
||||
|
||||
@@ -564,12 +614,13 @@ const sameConditionValue = (
|
||||
return String (condition.month)
|
||||
case 'original-month-day':
|
||||
return condition.monthDay
|
||||
case 'title-length-greater-than':
|
||||
return String (condition.length)
|
||||
case 'title-has-ascii':
|
||||
return ''
|
||||
case 'post-similarity':
|
||||
return `${ condition.postId }:${ condition.answer }:${ condition.threshold }`
|
||||
case 'title-length-at-least':
|
||||
case 'title-length-greater-than':
|
||||
return String (titleLengthMinimumForCondition (condition) ?? '')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -591,6 +642,38 @@ const monthForCondition = (
|
||||
}
|
||||
|
||||
|
||||
const isTitleLengthContradiction = (
|
||||
candidate: GekanatorQuestion['condition'],
|
||||
previous: GekanatorQuestion['condition'],
|
||||
answer: GekanatorAnswerValue,
|
||||
): boolean => {
|
||||
const candidateLength = titleLengthMinimumForCondition (candidate)
|
||||
const previousLength = titleLengthMinimumForCondition (previous)
|
||||
if (candidateLength === null || previousLength === null)
|
||||
return false
|
||||
|
||||
switch (answer)
|
||||
{
|
||||
case 'yes':
|
||||
return candidateLength <= previousLength
|
||||
case 'no':
|
||||
return candidateLength >= previousLength
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const isQuestionRedundantAfterAnswers = (
|
||||
question: GekanatorQuestion,
|
||||
answers: GekanatorAnswerLog[],
|
||||
): boolean => answers.some (answer => {
|
||||
const previous = answer.questionCondition
|
||||
return previous !== undefined
|
||||
&& isTitleLengthContradiction (question.condition, previous, answer.answer)
|
||||
})
|
||||
|
||||
|
||||
const isMonthCrossMatch = (
|
||||
candidate: GekanatorQuestion['condition'],
|
||||
previous: GekanatorQuestion['condition'],
|
||||
@@ -725,6 +808,9 @@ const chooseQuestion = ({
|
||||
|
||||
return questionsToRank
|
||||
.map (question => {
|
||||
if (isQuestionRedundantAfterAnswers (question, answers))
|
||||
return null
|
||||
|
||||
const signature = signatureFor (question, candidates)
|
||||
if (redundant.has (signature))
|
||||
return null
|
||||
|
||||
新しい課題から参照
ユーザをブロックする