このコミットが含まれているのは:
+48
-60
@@ -17,11 +17,9 @@ export type GekanatorAnswerLog = {
|
||||
|
||||
export type GekanatorQuestionKind =
|
||||
| 'tag'
|
||||
| 'title'
|
||||
| 'date'
|
||||
| 'media'
|
||||
| 'source'
|
||||
| 'structure'
|
||||
| 'title'
|
||||
| 'original_date'
|
||||
|
||||
export type GekanatorQuestion = {
|
||||
id: string
|
||||
@@ -54,6 +52,19 @@ const hostOf = (post: Post): string | null => {
|
||||
}
|
||||
|
||||
|
||||
const originalYearOf = (post: Post): number | null => {
|
||||
const value = post.originalCreatedFrom || post.originalCreatedBefore
|
||||
if (!(value))
|
||||
return null
|
||||
|
||||
const date = new Date (value)
|
||||
if (Number.isNaN (date.getTime ()))
|
||||
return null
|
||||
|
||||
return date.getFullYear ()
|
||||
}
|
||||
|
||||
|
||||
const tagQuestionKey = ({ category, name }: { category: string; name: string }): string =>
|
||||
`${ category }:${ name }`
|
||||
|
||||
@@ -113,9 +124,11 @@ export const buildGekanatorQuestions = (posts: Post[]): GekanatorQuestion[] => {
|
||||
&& !(tag.name.includes ('bot操作')))
|
||||
.map (tag => tagQuestionKey (tag))))
|
||||
const hosts = countBy (posts.map (hostOf).filter ((host): host is string => Boolean (host)))
|
||||
const tagMedian = median (posts.map (post => post.tags.length))
|
||||
const originalYears = countBy (
|
||||
posts
|
||||
.map (originalYearOf)
|
||||
.filter ((year): year is number => year !== null))
|
||||
const titleLengthMedian = median (posts.map (post => post.title?.length ?? 0))
|
||||
const currentYear = new Date ().getFullYear ()
|
||||
|
||||
const usefulEntries = <T extends string | number> (counts: Map<T, number>) =>
|
||||
[...counts.entries ()]
|
||||
@@ -144,63 +157,41 @@ export const buildGekanatorQuestions = (posts: Post[]): GekanatorQuestion[] => {
|
||||
.filter (([, count]) => count >= 2 && count <= Math.max (2, posts.length * .7))
|
||||
.slice (0, 20)
|
||||
.map (([host]) => ({
|
||||
id: `source:${ host }`,
|
||||
text: `${ host } の投稿を思ひ浮かべてゐる?`,
|
||||
kind: 'source' as const,
|
||||
test: (post: Post) => hostOf (post) === host }))
|
||||
id: `source:${ host }`,
|
||||
text: `${ host } の投稿を思ひ浮かべてゐる?`,
|
||||
kind: 'source' as const,
|
||||
test: (post: Post) => hostOf (post) === host }))
|
||||
|
||||
return [
|
||||
...sourceQuestions,
|
||||
{
|
||||
id: 'title:present',
|
||||
text: '題名が付いてゐる投稿?',
|
||||
kind: 'title',
|
||||
test: post => Boolean (post.title) },
|
||||
const originalYearQuestions = usefulEntries (originalYears)
|
||||
.filter (([, count]) => count >= 2 && count <= Math.max (2, posts.length * .7))
|
||||
.slice (0, 20)
|
||||
.map (([year]) => ({
|
||||
id: `original-year:${ year }`,
|
||||
text: `オリジナルの投稿年は ${ year } 年?`,
|
||||
kind: 'original_date' as const,
|
||||
test: (post: Post) => originalYearOf (post) === year }))
|
||||
|
||||
const titleQuestions = [
|
||||
{
|
||||
id: 'title:long',
|
||||
text: '題名が長めの投稿?',
|
||||
kind: 'title',
|
||||
test: post => (post.title?.length ?? 0) > titleLengthMedian },
|
||||
kind: 'title' as const,
|
||||
test: (post: Post) => (post.title?.length ?? 0) > titleLengthMedian },
|
||||
{
|
||||
id: 'title:ascii',
|
||||
text: '題名に英数字が混じってゐる?',
|
||||
kind: 'title',
|
||||
test: post => /[A-Za-z0-9]/.test (post.title ?? '') },
|
||||
{
|
||||
id: 'media:thumbnail',
|
||||
text: 'ぱっと見でサムネが付いてゐる投稿?',
|
||||
kind: 'media',
|
||||
test: post => Boolean (post.thumbnail || post.thumbnailBase) },
|
||||
{
|
||||
id: 'media:video-source',
|
||||
text: '動画として見られる投稿?',
|
||||
kind: 'media',
|
||||
test: post => /nicovideo|youtube|youtu\.be/.test (post.url) },
|
||||
{
|
||||
id: 'structure:many-tags',
|
||||
text: 'タグが多めに付いてゐる投稿?',
|
||||
kind: 'structure',
|
||||
test: post => post.tags.length > tagMedian },
|
||||
{
|
||||
id: 'structure:no-title',
|
||||
text: '題名がまだ付いてゐない投稿?',
|
||||
kind: 'structure',
|
||||
test: post => !(post.title) },
|
||||
{
|
||||
id: 'date:recent',
|
||||
text: '最近追加されたほうの投稿?',
|
||||
kind: 'date',
|
||||
test: post => new Date (post.createdAt).getFullYear () >= currentYear - 1 },
|
||||
{
|
||||
id: 'date:old',
|
||||
text: 'むかし追加されたほうの投稿?',
|
||||
kind: 'date',
|
||||
test: post => new Date (post.createdAt).getFullYear () <= currentYear - 3 },
|
||||
{
|
||||
id: 'date:original-known',
|
||||
text: 'オリジナルの投稿日時が分かってゐる投稿?',
|
||||
kind: 'date',
|
||||
test: post => Boolean (post.originalCreatedFrom || post.originalCreatedBefore) },
|
||||
kind: 'title' as const,
|
||||
test: (post: Post) => /[A-Za-z0-9]/.test (post.title ?? '') }]
|
||||
.filter (question => {
|
||||
const yes = posts.filter (post => question.test (post)).length
|
||||
const no = posts.length - yes
|
||||
return yes >= 2 && no >= 2 && yes <= posts.length * .7 && no <= posts.length * .7
|
||||
})
|
||||
|
||||
return [
|
||||
...sourceQuestions,
|
||||
...originalYearQuestions,
|
||||
...titleQuestions,
|
||||
...tagQuestions]
|
||||
}
|
||||
|
||||
@@ -208,18 +199,15 @@ export const buildGekanatorQuestions = (posts: Post[]): GekanatorQuestion[] => {
|
||||
export const saveGekanatorGame = async ({
|
||||
guessedPostId,
|
||||
correctPostId,
|
||||
won,
|
||||
answers,
|
||||
}: {
|
||||
guessedPostId: number
|
||||
correctPostId: number | null
|
||||
won: boolean
|
||||
correctPostId: number
|
||||
answers: GekanatorAnswerLog[]
|
||||
}): Promise<{ id: number }> =>
|
||||
await apiPost ('/gekanator/games', {
|
||||
guessed_post_id: guessedPostId,
|
||||
correct_post_id: correctPostId,
|
||||
won,
|
||||
question_count: answers.length,
|
||||
answers: answers.map (answer => ({
|
||||
question_id: answer.questionId,
|
||||
|
||||
新しい課題から参照
ユーザをブロックする