Fix duplicate picks and recursive rating updates

This commit is contained in:
Maciej Pędzich 2023-06-09 12:57:53 +02:00
parent 053e4e0302
commit 5cc46fbd6b
2 changed files with 86 additions and 76 deletions

View File

@ -1,13 +1,13 @@
import { computed, reactive, ref, toRefs } from 'vue'; import { computed, reactive, ref, toRefs, watchEffect } from 'vue';
import glicko2 from 'glicko2-lite'; import glicko2 from 'glicko2-lite';
import photos from '@/photos.json'; import defaultPhotos from '@/photos.json';
import { Database, Photo } from '@/models'; import { Database, Photo } from '@/models';
import { randomNumber } from '@/utils/randomNumber'; import { randomNumber } from '@/utils/randomNumber';
const db = reactive<Database>( const db = reactive<Database>(
JSON.parse(localStorage.getItem('db') as string) || { JSON.parse(localStorage.getItem('db') as string) || {
photos, photos: defaultPhotos,
votes: [] votes: []
} }
); );
@ -24,7 +24,6 @@ const photosForFirstPick = computed(() =>
}) })
); );
export function useVote() {
const pickPhotosForNewVote = () => { const pickPhotosForNewVote = () => {
const firstPick = const firstPick =
photosForFirstPick.value[ photosForFirstPick.value[
@ -37,7 +36,11 @@ export function useVote() {
); );
const fileNamesToExclude = [ const fileNamesToExclude = [
...new Set(votesWithFirstPick.flatMap(({ photos }) => photos)) ...new Set(
votesWithFirstPick
.flatMap(({ photos }) => photos)
.concat([firstPick.fileName])
)
]; ];
return !fileNamesToExclude.includes(fileName); return !fileNamesToExclude.includes(fileName);
@ -46,16 +49,20 @@ export function useVote() {
const secondPick = const secondPick =
photosForSecondPick[randomNumber(0, photosForSecondPick.length - 1)]; photosForSecondPick[randomNumber(0, photosForSecondPick.length - 1)];
photosInCurrentVote.value.push(firstPick, secondPick); photosInCurrentVote.value = [firstPick, secondPick];
}; };
const submitVote = (result: 0 | 0.5 | 1) => { const submitVote = (result: 0 | 0.5 | 1) => {
const fileNames = [...photosInCurrentVote.value].map( const fileNames = ([...photosInCurrentVote.value] as Photo[]).map(
({ fileName }) => fileName ({ fileName }) => fileName
) as [string, string]; ) as [string, string];
db.votes.unshift({ photos: fileNames, result }); db.votes.unshift({ photos: fileNames, result });
photosInCurrentVote.value = [];
if (db.votes.length % 12 === 0) {
updateRatings();
}
pickPhotosForNewVote(); pickPhotosForNewVote();
}; };
@ -63,13 +70,14 @@ export function useVote() {
const twelveMostRecentVotes = db.votes.slice(0, 12).reverse(); const twelveMostRecentVotes = db.votes.slice(0, 12).reverse();
const votesGrouppedByPhotos = twelveMostRecentVotes.reduce((obj, vote) => { const votesGrouppedByPhotos = twelveMostRecentVotes.reduce((obj, vote) => {
const [firstPick, secondPick] = vote.photos; const [firstFileName, secondFileName] = vote.photos;
const firstPhoto = db.photos.find( const firstPhoto = db.photos.find(
({ fileName }) => fileName === firstPick ({ fileName }) => fileName === firstFileName
)!; )!;
const secondPhoto = db.photos.find( const secondPhoto = db.photos.find(
({ fileName }) => fileName === secondPick ({ fileName }) => fileName === secondFileName
)!; )!;
const firstPhotoOpponentParams = [ const firstPhotoOpponentParams = [
@ -84,33 +92,32 @@ export function useVote() {
1 - vote.result 1 - vote.result
] as [number, number, number]; ] as [number, number, number];
if (obj[firstPick]) { if (obj[firstFileName]) {
obj[firstPick].push(firstPhotoOpponentParams); obj[firstFileName].push(firstPhotoOpponentParams);
} else { } else {
obj[firstPick] = [firstPhotoOpponentParams]; obj[firstFileName] = [firstPhotoOpponentParams];
} }
if (obj[secondPick]) { if (obj[secondFileName]) {
obj[secondPick].push(secondPhotoOpponentParams); obj[secondFileName].push(secondPhotoOpponentParams);
} else { } else {
obj[secondPick] = [secondPhotoOpponentParams]; obj[secondFileName] = [secondPhotoOpponentParams];
} }
return obj; return obj;
}, {} as Record<string, [number, number, number][]>); }, {} as Record<string, [number, number, number][]>);
for (const [photoFileName, votes] of Object.entries( for (const [photoFileName, votes] of Object.entries(votesGrouppedByPhotos)) {
votesGrouppedByPhotos const photo = db.photos.find(({ fileName }) => fileName === photoFileName)!;
)) {
const photo = db.photos.find(
({ fileName }) => fileName === photoFileName
)!;
const newRatingParams = glicko2(photo.rating, photo.rd, photo.vol, votes); const newRatingParams = glicko2(photo.rating, photo.rd, photo.vol, votes);
Object.assign(photo, newRatingParams); Object.assign(photo, newRatingParams);
} }
}; };
watchEffect(() => localStorage.setItem('db', JSON.stringify(db)));
export function useVote() {
return { return {
photosInCurrentVote, photosInCurrentVote,
photosForFirstPick, photosForFirstPick,

File diff suppressed because one or more lines are too long