From 58eb6ec4dc8f49a0c5eeee8ee97d39b951d031a3 Mon Sep 17 00:00:00 2001 From: steel <mael.acier@ensiie.fr> Date: Sun, 1 Sep 2024 23:54:28 +0200 Subject: [PATCH] feat: variable score --- src/lib/game.ts | 7 +++++-- src/routes/quiz/+page.server.ts | 22 ++++++++++++++++++---- src/routes/quiz/+page.svelte | 27 ++++++++++++++++++++------- 3 files changed, 43 insertions(+), 13 deletions(-) diff --git a/src/lib/game.ts b/src/lib/game.ts index e20f14d..85fa5c1 100644 --- a/src/lib/game.ts +++ b/src/lib/game.ts @@ -19,7 +19,8 @@ export const gameStateSchema = z.object({ year: z.number(), maxYear: z.number().optional(), label: z.string(), - solution: z.string() + solution: z.string(), + timestamp: z.number() }); export type GameState = z.infer<typeof gameStateSchema>; @@ -44,12 +45,14 @@ export class Game { year: 0, options: [], solution: '', - label: '?' + label: '?', + timestamp: 0 }; } save() { // console.log('SAVE:', GameStage[this.state.stage], this.state); + this.state.timestamp = Date.now(); this.cookie.write(this.state); } diff --git a/src/routes/quiz/+page.server.ts b/src/routes/quiz/+page.server.ts index db2214e..ce29c90 100644 --- a/src/routes/quiz/+page.server.ts +++ b/src/routes/quiz/+page.server.ts @@ -62,6 +62,19 @@ export async function load(event) { }; } +const MAX_POINTS = 10; +const MIN_POINTS = 0; +// Durée maximale pour obtenir le score maximal +const SERVER_DELAY_MAX = 3; + +function computePoints(timestamp: number): number { + const elapsed = (Date.now() - timestamp) / 1000; + return Math.max( + MIN_POINTS, + Math.floor(MAX_POINTS - Math.min(MAX_POINTS + SERVER_DELAY_MAX, elapsed)) + ); +} + export const actions = { async results(event) { const form = await superValidate(event, zod(schema)); @@ -72,15 +85,16 @@ export const actions = { const state = new Game(event.cookies); - if (form.data.choice === state.state.solution) { - state.state.score += 10; - } + const points = + form.data.choice === state.state.solution ? computePoints(state.state.timestamp) : 0; + state.state.score += points; state.state.history.push(state.state.solution); state.save(); return { form, - solution: state.state.solution + solution: state.state.solution, + points }; }, diff --git a/src/routes/quiz/+page.svelte b/src/routes/quiz/+page.svelte index 4533b4c..a0f2d9b 100644 --- a/src/routes/quiz/+page.svelte +++ b/src/routes/quiz/+page.svelte @@ -1,6 +1,7 @@ <script lang="ts"> import { Fieldset, Control, Label } from 'formsnap'; import { superForm } from 'sveltekit-superforms'; + import { scale } from 'svelte/transition'; export let data; export let form; @@ -17,7 +18,7 @@ <div class="relative mx-auto my-12 w-full grow"> <section class="relative m-auto flex flex-col items-center"> - <h1 class="absolute -top-8 text-xl">Qui est-ce ? {data.label}</h1> + <h1 class="absolute -top-8 text-xl">Qui est-ce ?</h1> <div class="relative"> <span class="absolute right-[calc(100%_+_0.5rem)] text-right"> <span class="flex flex-col items-end"> @@ -27,14 +28,20 @@ <span class="inline-block h-1.5 w-10 bg-zinc-800"></span> <br /> <span class="top-24 pt-4 text-xl text-zinc-800"> - {data.score} + {data.score - (form?.points ?? 0)} <small>pts</small> </span> </span> - <div - class="relative z-10 flex h-64 w-64 items-center justify-center overflow-hidden rounded-2xl border-6 border-solid border-zinc-800 bg-white before:absolute before:-z-10 before:h-32 before:w-32 before:rounded-full before:bg-slate-300 before:opacity-100 before:transition-[0.65s] before:duration-[ease-in-out] after:absolute after:-z-10 after:h-32 after:w-32 after:scale-0 after:rounded-full after:border-solid after:border-slate-300 after:transition-[0.4s] after:duration-[ease-in-out]" - > - <img src={data.photo?.url} alt="Chargement..." class="w-auto" /> + <div> + <div + class="relative z-10 flex h-64 w-64 items-center justify-center overflow-hidden rounded-2xl border-6 border-solid border-zinc-800 bg-white before:absolute before:-z-10 before:h-32 before:w-32 before:rounded-full before:bg-slate-300 before:opacity-100 before:transition-[0.65s] before:duration-[ease-in-out] after:absolute after:-z-10 after:h-32 after:w-32 after:scale-0 after:rounded-full after:border-solid after:border-slate-300 after:transition-[0.4s] after:duration-[ease-in-out]" + > + <img src={data.photo?.url} alt="Chargement..." class="w-auto" /> + </div> + <span + class="absolute left-0 top-0 z-20 rounded-br-xl rounded-tl-2xl bg-zinc-800 px-2 text-xl text-white" + >{data.label}</span + > </div> <form method="post" use:enhance> <Fieldset form={sForm} name="choice"> @@ -42,6 +49,7 @@ class="relative -top-6 z-20 mx-auto my-0 flex w-44 flex-col items-center space-y-0.5 rounded-2xl bg-zinc-800 px-5 py-0" > {#each data.options as option} + {@const valid = (form?.solution && option.value === form?.solution) || null} <div class="max-h-14 w-full min-w-52"> <Control let:attrs> <input @@ -51,13 +59,18 @@ value={option.value} class="peer sr-only" disabled={form?.solution !== undefined} - data-valid={(form?.solution && option.value === form?.solution) || null} + data-valid={valid} /> <Label tabindex={0} class="relative block cursor-pointer select-none overflow-hidden rounded-2xl border-6 border-solid border-zinc-800 bg-slate-300 p-2 text-center text-lg transition-[0.45s] before:absolute before:left-2/4 before:top-2/4 before:-z-10 before:h-[200px] before:w-[200px] before:-translate-x-2/4 before:-translate-y-2/4 before:scale-0 before:rounded-full before:bg-indigo-300 before:transition-[0.2s] before:duration-[ease-in-out] focus:[outline:none] active:before:-translate-x-2/4 active:before:-translate-y-2/4 active:before:scale-100 peer-enabled:hover:translate-y-[-3px] peer-enabled:hover:bg-slate-400 peer-enabled:focus:border-indigo-500 peer-checked:peer-enabled:bg-indigo-300 peer-disabled:cursor-default peer-disabled:text-[#94acbd] peer-checked:peer-disabled:bg-red-400 peer-checked:peer-disabled:text-inherit peer-data-[valid]:!bg-lime-400 peer-data-[valid]:text-inherit" > {option.label} + {#if valid && form?.points} + <span class="absolute right-0 mr-1.5 rounded-full bg-white px-1.5" in:scale> + +{form.points} + </span> + {/if} </Label> </Control> </div> -- GitLab