Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) {
Copy link
Copy Markdown
Contributor

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å.

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",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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>;
}
27 changes: 27 additions & 0 deletions apps/web/src/app/(default)/for-studenter/dagens-ord/page.tsx
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);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The 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;
}
Loading
Loading