-
Notifications
You must be signed in to change notification settings - Fork 5
første utkast av Dagens ord. Spillet burde fungere, men ikke lagt til… #3053
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| "use server"; | ||
|
|
||
| import { readFileSync } from "fs"; | ||
| import { join } from "path"; | ||
|
|
||
| export async function validWord(currentAttempt: string) { | ||
| if (currentAttempt.length !== 5) { | ||
| return; | ||
| } | ||
| const file = readFileSync( | ||
| join(process.cwd(), "src/app/(default)/for-studenter/dagens-ord/words.txt"), | ||
| "utf-8", | ||
| ); | ||
| const words = file.split("\n").filter(Boolean); | ||
|
|
||
| return words.includes(currentAttempt); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| "use client"; | ||
|
|
||
| import { useEffect, useState } from "react"; | ||
|
|
||
| import ConfettiForBDay from "../../../hjem/_components/confetti"; | ||
| import { validWord } from "../_actions/validere-ord"; | ||
| import Row from "./row"; | ||
|
|
||
| export default function DagensOrd({ solution }: { solution: string }) { | ||
| const [loss, setLoss] = useState(false); | ||
| const [attempts, setAttmpts] = useState(Array(6).fill("")); | ||
| const [currentAttempt, setCurrentAttemt] = useState(""); | ||
| const [currentRow, setCurrentRow] = useState(0); | ||
| const [win, setWin] = useState(false); | ||
| const [isVaildWord, setIsValidWord] = useState(true); | ||
|
|
||
| // Last lagret state ved oppstart | ||
| useEffect(() => { | ||
| const saved = localStorage.getItem("dagens-ord"); | ||
| if (saved) { | ||
| const data = JSON.parse(saved); | ||
| if (data.date === new Date().toDateString()) { | ||
| setAttmpts(data.attempts); | ||
| setCurrentRow(data.currentRow); | ||
| setWin(data.win); | ||
| setLoss(data.loss); | ||
| } | ||
| } | ||
| }, []); | ||
|
|
||
| // Lagre state etter hvert forsøk | ||
| useEffect(() => { | ||
| if (currentRow > 0 || win || loss) { | ||
| localStorage.setItem( | ||
| "dagens-ord", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Kanskje lage en egen type for spill state så det er lettere å ha oversikt over + blir litt cleanere. |
||
| JSON.stringify({ | ||
| date: new Date().toDateString(), | ||
| attempts, | ||
| currentRow, | ||
| win, | ||
| loss, | ||
| }), | ||
| ); | ||
| } | ||
| }, [attempts, currentRow, win, loss]); | ||
|
|
||
| //Spillogikk | ||
| useEffect(() => { | ||
| if (win) { | ||
| return; | ||
| } | ||
| const handeKeyPressed = async (event: KeyboardEvent) => { | ||
| if (event.key === "Enter" && currentAttempt.length === 5) { | ||
| const isValid = await validWord(currentAttempt); | ||
| if (!isValid) { | ||
| setIsValidWord(false); | ||
| return; | ||
| } | ||
|
|
||
| setAttmpts(attempts.map((a, i) => (i === currentRow ? currentAttempt : a))); | ||
| setCurrentRow(currentRow + 1); | ||
| setCurrentAttemt(""); | ||
| setIsValidWord(true); | ||
| if (solution === currentAttempt) { | ||
| setWin(true); | ||
| } else if (currentRow === 5) { | ||
| setLoss(true); | ||
| return; | ||
| } | ||
| } else if (event.key === "Backspace") { | ||
| setCurrentAttemt(currentAttempt.slice(0, -1)); | ||
| } else if (/^[a-zA-ZæøåÆØÅ]$/.test(event.key) && currentAttempt.length < 5) { | ||
| setCurrentAttemt(currentAttempt + event.key.toLowerCase()); | ||
| } | ||
| }; | ||
|
|
||
| window.addEventListener("keydown", handeKeyPressed); | ||
|
|
||
| return () => window.removeEventListener("keydown", handeKeyPressed); | ||
| }, [currentAttempt, currentRow, attempts, win, solution]); | ||
|
|
||
| return ( | ||
| <> | ||
| {win && <ConfettiForBDay />} | ||
| <h1 className="self-center p-3 text-4xl">Dagens ord</h1> | ||
| {!isVaildWord && ( | ||
| <p className="self-center p-3 text-2xl font-bold">Ordet er ikke i listen, prøv igjen</p> | ||
| )} | ||
|
|
||
| <div> | ||
| {attempts.map((attempt, index) => { | ||
| const isCuurentAttempt = index === currentRow; | ||
| return ( | ||
| <Row | ||
| key={index} | ||
| attempt={isCuurentAttempt ? currentAttempt : attempt} | ||
| solution={solution} | ||
| submitted={index < currentRow || win} | ||
| /> | ||
| ); | ||
| })} | ||
| </div> | ||
| {loss && <p className="self-center text-2xl font-bold">{`Korrekt ord var ${solution}`}</p>} | ||
| </> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| function getTileColor(char: string, index: number, solution: string) { | ||
| if (!char) return ""; | ||
| if (solution[index] === char) return "bg-green-500 text-white border-green-500"; | ||
| if (solution.includes(char)) return "bg-yellow-500 text-white border-yellow-500"; | ||
| return "bg-gray-500 text-white border-gray-500"; | ||
| } | ||
|
|
||
| export default function Row({ | ||
| attempt, | ||
| solution, | ||
| submitted, | ||
| }: { | ||
| attempt: string; | ||
| solution: string; | ||
| submitted: boolean; | ||
| }) { | ||
| const WORD_LENGHT = 5; | ||
| const tiles = []; | ||
|
|
||
| for (let i = 0; i < WORD_LENGHT; i++) { | ||
| const char = attempt[i] ?? ""; | ||
| const color = submitted ? getTileColor(char, i, solution) : ""; | ||
|
|
||
| tiles.push( | ||
| <div | ||
| key={i} | ||
| className={`m-1 flex h-18 w-18 items-center justify-center border-2 border-gray-400 text-5xl uppercase ${color}`} | ||
| > | ||
| {char} | ||
| </div>, | ||
| ); | ||
| } | ||
|
|
||
| return <div className="flex- flex justify-center">{tiles}</div>; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| import { readFileSync } from "fs"; | ||
| import { join } from "path"; | ||
|
|
||
| import DagensOrd from "./_components/dagens-ord"; | ||
|
|
||
| export default function DagensOrdPage() { | ||
| const file = readFileSync( | ||
| join(process.cwd(), "src/app/(default)/for-studenter/dagens-ord/words.txt"), | ||
| "utf-8", | ||
| ); | ||
| const words = seededShuffle(file.split("\n").filter(Boolean), 42); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Det jeg mente med shuffle er at filen shuffles 1 gang før du lagrer den og shipper, og så aldri igjen. Så bare plukker du ut linje n og da blir det random uten noe som helst IO eller beregning. |
||
| const today = new Date(); | ||
| const dayIndex = Math.floor(today.getTime() / (1000 * 60 * 60 * 24)); | ||
| const solution = words[dayIndex % words.length] ?? "skole"; | ||
|
|
||
| return <DagensOrd solution={solution} />; | ||
| } | ||
|
|
||
| function seededShuffle(arr: Array<string>, seed: number) { | ||
| const shuffled = [...arr]; | ||
| for (let i = shuffled.length - 1; i > 0; i--) { | ||
| seed = (seed * 16807 + 0) % 2147483647; | ||
| const j = seed % (i + 1); | ||
| [shuffled[i], shuffled[j]] = [shuffled[j]!, shuffled[i]!]; | ||
| } | ||
| return shuffled; | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dette er en velidig sløsbar måte å skjekke på. Nå leses filen hver gang (fil-IO er tregt).
Heller les den inn globalt én gang (eller hent den fra uno) og lagre alle ord i et hash set. Da er lookup veldig raskt og filen lastes bare én gang.
Filen er bare 32kb så det går fint å sende den fra uno, men også OK å bare lagre den i next også.