improved social questions
This commit is contained in:
parent
834db89c9e
commit
e4e392de51
4 changed files with 79 additions and 18 deletions
|
|
@ -83,7 +83,11 @@ export type QuizState = {
|
|||
};
|
||||
|
||||
export type PartySocketEvent =
|
||||
| { type: "party_status"; party: Party|null; members: PartyMemberWithUser[] }
|
||||
| {
|
||||
type: "party_status";
|
||||
party: Party | null;
|
||||
members: PartyMemberWithUser[];
|
||||
}
|
||||
| { type: "member_payload"; fromUserId: string; payload: unknown }
|
||||
| { type: "error"; message: string }
|
||||
| { type: "pong" };
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export type PartyAnalytics = {
|
|||
name: string;
|
||||
artists?: { name: string }[];
|
||||
albumName?: string;
|
||||
memberScores?: { userId: string; score: number }[];
|
||||
}[];
|
||||
artists?: { name: string }[];
|
||||
genres?: { name: string }[];
|
||||
|
|
@ -95,12 +96,28 @@ export function getTopClusterArtists(analytics: PartyAnalytics): string[] {
|
|||
);
|
||||
}
|
||||
|
||||
export function getTopClusterTracks(
|
||||
analytics: PartyAnalytics,
|
||||
): Array<{ name: string; artists?: { name: string }[]; albumName?: string }> {
|
||||
export function getTopClusterTracks(analytics: PartyAnalytics): Array<{
|
||||
name: string;
|
||||
artists?: { name: string }[];
|
||||
albumName?: string;
|
||||
memberScores?: { userId: string; score: number }[];
|
||||
}> {
|
||||
return analytics?.storyClusters?.[0]?.tracks ?? [];
|
||||
}
|
||||
|
||||
export function getTopTrackListener(
|
||||
track: { memberScores?: { userId: string; score: number }[] },
|
||||
members: PartyQuestionMember[],
|
||||
): PartyQuestionMember | null {
|
||||
const topMember = (track.memberScores ?? [])
|
||||
.slice()
|
||||
.sort((a, b) => b.score - a.score)
|
||||
.at(0);
|
||||
|
||||
if (!topMember) return null;
|
||||
return members.find((member) => member.userId === topMember.userId) ?? null;
|
||||
}
|
||||
|
||||
export function buildOrderedOptions(
|
||||
values: Array<string | undefined>,
|
||||
desiredCount: number,
|
||||
|
|
@ -143,6 +160,17 @@ export function getCurrentLeader(
|
|||
);
|
||||
}
|
||||
|
||||
export function hasClearLeader(quizState: {
|
||||
scores: Record<string, number>;
|
||||
}): boolean {
|
||||
const scores = Object.values(quizState.scores);
|
||||
if (scores.length < 2) return false;
|
||||
const ordered = scores.slice().sort((a, b) => b - a);
|
||||
const [first, second] = ordered;
|
||||
if (first === undefined || second === undefined) return false;
|
||||
return first > second;
|
||||
}
|
||||
|
||||
export function getMostDiverseMember(
|
||||
analytics: PartyAnalytics,
|
||||
members: PartyQuestionMember[],
|
||||
|
|
|
|||
|
|
@ -5,8 +5,12 @@ import {
|
|||
getCurrentLeader,
|
||||
getMostAlignedMember,
|
||||
getMostDiverseMember,
|
||||
getTopClusterTracks,
|
||||
getTopTrackListener,
|
||||
hasClearLeader,
|
||||
type PartyAnalytics,
|
||||
type PartyQuestionMember,
|
||||
pickRandom,
|
||||
} from "./question-utils";
|
||||
|
||||
export function buildSocialQuestion(
|
||||
|
|
@ -16,35 +20,60 @@ export function buildSocialQuestion(
|
|||
index: number,
|
||||
): Question {
|
||||
type ChoiceQuestion = Extract<Question, { type: "choice" }>;
|
||||
const leader = getCurrentLeader(quizState, members);
|
||||
const diverse = getMostDiverseMember(analytics, members);
|
||||
const aligned = getMostAlignedMember(analytics, members);
|
||||
|
||||
const questions: Array<
|
||||
Omit<ChoiceQuestion, "startTimestamp" | "endTimestamp">
|
||||
> = [
|
||||
{
|
||||
> = [];
|
||||
|
||||
const hasMultipleMembers = members.length >= 2;
|
||||
if (hasMultipleMembers && hasClearLeader(quizState)) {
|
||||
const leader = getCurrentLeader(quizState, members);
|
||||
questions.push({
|
||||
type: "choice",
|
||||
text: "Who is leading the quiz right now?",
|
||||
options: buildMemberOptions(leader, members),
|
||||
correct: 0,
|
||||
points: 10,
|
||||
},
|
||||
{
|
||||
});
|
||||
}
|
||||
|
||||
if (hasMultipleMembers) {
|
||||
const diverse = getMostDiverseMember(analytics, members);
|
||||
questions.push({
|
||||
type: "choice",
|
||||
text: "Who looks like the most diverse listener in the party?",
|
||||
options: buildMemberOptions(diverse, members),
|
||||
correct: 0,
|
||||
points: 10,
|
||||
},
|
||||
{
|
||||
});
|
||||
|
||||
const aligned = getMostAlignedMember(analytics, members);
|
||||
questions.push({
|
||||
type: "choice",
|
||||
text: "Which member seems most aligned with the rest of the party?",
|
||||
options: buildMemberOptions(aligned, members),
|
||||
correct: 0,
|
||||
points: 10,
|
||||
},
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
const topTracks = getTopClusterTracks(analytics);
|
||||
const randomTrack = pickRandom(topTracks);
|
||||
if (randomTrack && hasMultipleMembers) {
|
||||
const topListener = getTopTrackListener(randomTrack, members);
|
||||
if (topListener) {
|
||||
questions.push({
|
||||
type: "choice",
|
||||
text: `Who listens the most to "${randomTrack.name}"?`,
|
||||
options: buildMemberOptions(topListener, members),
|
||||
correct: 0,
|
||||
points: 10,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (questions.length === 0) {
|
||||
throw new Error("Question not found");
|
||||
}
|
||||
|
||||
const question = questions[index % questions.length];
|
||||
if (!question) throw new Error("Question not found");
|
||||
|
|
|
|||
|
|
@ -101,9 +101,9 @@ export class QuizWorkflow extends ConfiguredInstance {
|
|||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (receivedPlayers.has(response.playerId)) continue;
|
||||
if (receivedPlayers.has(response.playerId)) continue;
|
||||
|
||||
receivedPlayers.add(response.playerId);
|
||||
const answeredAt = Date.now();
|
||||
|
|
|
|||
Loading…
Reference in a new issue