mirror of
https://github.com/maciejpedzich/racemash.git
synced 2024-11-28 00:25:47 +01:00
Fix duplicate picks and recursive rating updates
This commit is contained in:
parent
053e4e0302
commit
5cc46fbd6b
@ -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,93 +24,100 @@ const photosForFirstPick = computed(() =>
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
export function useVote() {
|
const pickPhotosForNewVote = () => {
|
||||||
const pickPhotosForNewVote = () => {
|
const firstPick =
|
||||||
const firstPick =
|
photosForFirstPick.value[
|
||||||
photosForFirstPick.value[
|
randomNumber(0, photosForFirstPick.value.length - 1)
|
||||||
randomNumber(0, photosForFirstPick.value.length - 1)
|
];
|
||||||
];
|
|
||||||
|
|
||||||
const photosForSecondPick = db.photos.filter(({ fileName }) => {
|
const photosForSecondPick = db.photos.filter(({ fileName }) => {
|
||||||
const votesWithFirstPick = db.votes.filter(({ photos }) =>
|
const votesWithFirstPick = db.votes.filter(({ photos }) =>
|
||||||
photos.includes(firstPick.fileName)
|
photos.includes(firstPick.fileName)
|
||||||
);
|
);
|
||||||
|
|
||||||
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);
|
||||||
});
|
});
|
||||||
|
|
||||||
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 = [];
|
|
||||||
pickPhotosForNewVote();
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateRatings = () => {
|
if (db.votes.length % 12 === 0) {
|
||||||
const twelveMostRecentVotes = db.votes.slice(0, 12).reverse();
|
updateRatings();
|
||||||
|
}
|
||||||
|
|
||||||
const votesGrouppedByPhotos = twelveMostRecentVotes.reduce((obj, vote) => {
|
pickPhotosForNewVote();
|
||||||
const [firstPick, secondPick] = vote.photos;
|
};
|
||||||
|
|
||||||
const firstPhoto = db.photos.find(
|
const updateRatings = () => {
|
||||||
({ fileName }) => fileName === firstPick
|
const twelveMostRecentVotes = db.votes.slice(0, 12).reverse();
|
||||||
)!;
|
|
||||||
const secondPhoto = db.photos.find(
|
|
||||||
({ fileName }) => fileName === secondPick
|
|
||||||
)!;
|
|
||||||
|
|
||||||
const firstPhotoOpponentParams = [
|
const votesGrouppedByPhotos = twelveMostRecentVotes.reduce((obj, vote) => {
|
||||||
secondPhoto.rating,
|
const [firstFileName, secondFileName] = vote.photos;
|
||||||
secondPhoto.rd,
|
|
||||||
vote.result
|
|
||||||
] as [number, number, number];
|
|
||||||
|
|
||||||
const secondPhotoOpponentParams = [
|
const firstPhoto = db.photos.find(
|
||||||
firstPhoto.rating,
|
({ fileName }) => fileName === firstFileName
|
||||||
firstPhoto.rd,
|
)!;
|
||||||
1 - vote.result
|
|
||||||
] as [number, number, number];
|
|
||||||
|
|
||||||
if (obj[firstPick]) {
|
const secondPhoto = db.photos.find(
|
||||||
obj[firstPick].push(firstPhotoOpponentParams);
|
({ fileName }) => fileName === secondFileName
|
||||||
} else {
|
)!;
|
||||||
obj[firstPick] = [firstPhotoOpponentParams];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (obj[secondPick]) {
|
const firstPhotoOpponentParams = [
|
||||||
obj[secondPick].push(secondPhotoOpponentParams);
|
secondPhoto.rating,
|
||||||
} else {
|
secondPhoto.rd,
|
||||||
obj[secondPick] = [secondPhotoOpponentParams];
|
vote.result
|
||||||
}
|
] as [number, number, number];
|
||||||
|
|
||||||
return obj;
|
const secondPhotoOpponentParams = [
|
||||||
}, {} as Record<string, [number, number, number][]>);
|
firstPhoto.rating,
|
||||||
|
firstPhoto.rd,
|
||||||
|
1 - vote.result
|
||||||
|
] as [number, number, number];
|
||||||
|
|
||||||
for (const [photoFileName, votes] of Object.entries(
|
if (obj[firstFileName]) {
|
||||||
votesGrouppedByPhotos
|
obj[firstFileName].push(firstPhotoOpponentParams);
|
||||||
)) {
|
} else {
|
||||||
const photo = db.photos.find(
|
obj[firstFileName] = [firstPhotoOpponentParams];
|
||||||
({ fileName }) => fileName === photoFileName
|
|
||||||
)!;
|
|
||||||
const newRatingParams = glicko2(photo.rating, photo.rd, photo.vol, votes);
|
|
||||||
|
|
||||||
Object.assign(photo, newRatingParams);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
if (obj[secondFileName]) {
|
||||||
|
obj[secondFileName].push(secondPhotoOpponentParams);
|
||||||
|
} else {
|
||||||
|
obj[secondFileName] = [secondPhotoOpponentParams];
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}, {} as Record<string, [number, number, number][]>);
|
||||||
|
|
||||||
|
for (const [photoFileName, votes] of Object.entries(votesGrouppedByPhotos)) {
|
||||||
|
const photo = db.photos.find(({ fileName }) => fileName === photoFileName)!;
|
||||||
|
const newRatingParams = glicko2(photo.rating, photo.rd, photo.vol, votes);
|
||||||
|
|
||||||
|
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
Loading…
Reference in New Issue
Block a user