グカネータ作成 / ウィニング・ラン修正 (#41) #366
@@ -306,6 +306,10 @@ const chooseQuestion = ({
|
||||
const scoredPosts = posts
|
||||
.map (post => ({ post, score: scores.get (post.id) ?? 0 }))
|
||||
.sort ((a, b) => b.score - a.score)
|
||||
const topScore = scoredPosts[0]?.score ?? 0
|
||||
const nearTopCandidates = scoredPosts.filter (item => topScore - item.score <= 2)
|
||||
const focusCandidates =
|
||||
nearTopCandidates.length >= 2 && nearTopCandidates.length <= 8 ? nearTopCandidates : []
|
||||
|
||||
const signatureFor = (
|
||||
question: GekanatorQuestion,
|
||||
@@ -333,6 +337,7 @@ const chooseQuestion = ({
|
||||
const rank = (
|
||||
questionsToRank: GekanatorQuestion[],
|
||||
candidates: { post: Post; score: number }[],
|
||||
focusCandidates: { post: Post; score: number }[],
|
||||
) => {
|
||||
const redundant = redundantSignatures (candidates)
|
||||
const nonTagCount =
|
||||
@@ -349,25 +354,49 @@ const chooseQuestion = ({
|
||||
if (yes === 0 || no === 0)
|
||||
return null
|
||||
|
||||
const focusSignature = signatureFor (question, focusCandidates)
|
||||
const focusYes = focusSignature.split ('').filter (value => value === '1').length
|
||||
const focusNo = focusCandidates.length - focusYes
|
||||
const separatesFocus = focusCandidates.length >= 2 && focusYes > 0 && focusNo > 0
|
||||
|
||||
const splitScore = Math.abs (candidates.length / 2 - yes)
|
||||
const focusSplitScore = focusCandidates.length >= 2
|
||||
? Math.abs (focusCandidates.length / 2 - focusYes)
|
||||
: 0
|
||||
const tagPenalty = question.kind === 'tag' && nonTagCount < 4 ? 12 : 0
|
||||
const minSide = candidates.length < 10 ? 1 : Math.max (3, candidates.length * .08)
|
||||
const narrowPenalty = yes < minSide || no < minSide ? candidates.length : 0
|
||||
const focusPenalty =
|
||||
focusCandidates.length >= 2 && !(separatesFocus) ? candidates.length * 10 : 0
|
||||
|
||||
return { question,
|
||||
score: splitScore + tagPenalty + narrowPenalty,
|
||||
narrow: narrowPenalty > 0 }
|
||||
score: focusPenalty
|
||||
+ focusSplitScore * 20
|
||||
+ splitScore
|
||||
+ tagPenalty
|
||||
+ narrowPenalty,
|
||||
narrow: narrowPenalty > 0,
|
||||
separatesFocus }
|
||||
})
|
||||
.filter ((item): item is {
|
||||
question: GekanatorQuestion
|
||||
score: number
|
||||
narrow: boolean } => item !== null && Number.isFinite (item.score))
|
||||
question: GekanatorQuestion
|
||||
score: number
|
||||
narrow: boolean
|
||||
separatesFocus: boolean } => item !== null && Number.isFinite (item.score))
|
||||
.sort ((a, b) => a.score - b.score)
|
||||
}
|
||||
|
||||
const unansweredQuestions =
|
||||
questions.filter (question => !(askedIds.has (question.id)))
|
||||
const ranked = rank (unansweredQuestions, scoredPosts)
|
||||
const ranked = rank (unansweredQuestions, scoredPosts, focusCandidates)
|
||||
|
||||
if (focusCandidates.length >= 2)
|
||||
return (
|
||||
ranked.find (item => item.separatesFocus && !(item.narrow))
|
||||
?? ranked.find (item => item.separatesFocus)
|
||||
?? ranked.find (item => !(item.narrow))
|
||||
?? ranked[0]
|
||||
)?.question ?? null
|
||||
|
||||
return (ranked.find (item => !(item.narrow)) ?? ranked[0])?.question ?? null
|
||||
}
|
||||
|
||||
新しい課題から参照
ユーザをブロックする