Skip to content
Snippets Groups Projects
Commit ff5b2841 authored by BENCHIKH Ilhem's avatar BENCHIKH Ilhem
Browse files

td45

parent 4b7c6d0a
No related branches found
No related tags found
No related merge requests found
......@@ -15,10 +15,17 @@ export class ServerApp {
const fastify = new Fastify({logger: logEnabled});
fastify.register(fastifyView, {engine: {ejs: ejs}});
fastify.register(fastifyStatic, { root: new URL('static', import.meta.url) });
fastify.register(fastifyFormbody);
fastify.register(fastifyCookie);
fastify.register(fastifySession, {secret: '01234567890123456789012345678901', cookie: {secure: 'auto'}});
fastify.get("/", (request, reply) => this.getIndex(request, reply));
fastify.get("/level/:id(^\\d+$)", (request, reply) => this.getLevel(request, reply));
fastify.post("/level/:id(^\\d+$)",(request, reply) => this.postWord(request, reply));
fastify.setErrorHandler((error, request, reply) => {this.handleError(error, reply);});
fastify.setNotFoundHandler((request, reply) => {this.handleNotFound(reply);});
return fastify;
}
......@@ -36,12 +43,17 @@ export class ServerApp {
getLevel(request, reply) {
const id = parseInt(request.params.id, 10);
this.resetSessionIfNeeded(request);
const level = this.game.level(id);
const letters = this.game.letters(id);
const lines = request.session.lines;
reply.view('templates/level.ejs', {
id : id,
level: level,
letters: letters
letters: letters,
lines: lines
});
}
......@@ -59,4 +71,36 @@ export class ServerApp {
});
}
postWord(request, reply) {
const id = parseInt(request.params.id, 10);
const word = request.body.word;
this.resetSessionIfNeeded(request);
const level = this.game.level(id);
const letters = this.game.letters(id);
const line = this.game.computeLine(id, word);
request.session.lines.push(line);
console.log('Computed line:', line);
reply.redirect(`/level/${id}`);
/*reply.view("templates/level.ejs", {
id: id,
level: level,
letters: letters,
lines: request.session.lines
});
*/
}
resetSessionIfNeeded(request) {
if (!request.session.levelId || request.params.id !== request.session.levelId) {
request.session.levelId = request.params.id;
request.session.lines = [];
}
}
}
\ No newline at end of file
......@@ -27,13 +27,23 @@
<td class="text-bg-primary"><%= letters[i] %></td>
<% } %>
</tr>
<!-- TODO 5 -->
<% for (let i = 0; i < lines.length; i++) { %>
<tr>
<% for (let j = 0; j < lines[i].length; j++) { %>
<% if (lines[i][j].state) { %>
<td class="text-bg-success"><%= lines[i][j].letter %></td>
<% } else { %>
<td class="text-bg-danger"><%= lines[i][j].letter %></td>
<% } %>
<% } %>
</tr>
<% } %>
</tbody>
</table>
<form action="/level/<%= id %>" method="POST" class="mt-3">
<form action="/level/<%= level.id %>" method="POST" class="mt-3">
<div class=" input-group mb-3">
<input type="text" name="word" class="form-control" placeholder="Votre mot" required>
<button type="submit" class="btn btn-outline-secondary">Proposer</button>
<input type="text" name="word" class="form-control" placeholder="Entrez un mot" required>
<button typr="submit" class=" btn btn-outline-secondary">Proposer</button>
</div>
</form>
</div>
......
......@@ -9,12 +9,16 @@ import puppeteer from 'puppeteer';
let ServerGame = null;
let serverData = null;
let data = undefined;
let Game = null;
async function asyncImport() {
if (progression >= 28) {
Game = (await import('./static/game.js')).Game;
}
if (progression <= 47) {
data = (await import('./static/data.js')).data;
}
if (progression >= 39) {
ServerGame = (await import('./game.js')).Game;
serverData = (await import('./data.js')).data;
......@@ -67,7 +71,13 @@ if (progression >= 27) {
const browser = await puppeteer.launch();
const page = await browser.newPage();
const consoleLogs = [];
page.on('console', async consoleObj => { consoleLogs.push(await consoleObj.args()[0]?.jsonValue()) });
page.on('console', async consoleObj => {
const args = consoleObj.args();
const arg0 = args[0];
if (arg0 == undefined) return;
const json = await arg0.jsonValue();
consoleLogs.push(json);
});
await page.goto(`http://localhost:${fastify.server.address().port}`);
const content = await page.content();
const dom = new JSDOM(content);
......@@ -93,8 +103,9 @@ if (progression >= 28 && progression < 30) {
page.on('console', async consoleObj => {
const args = consoleObj.args();
const arg0 = args[0];
if (arg0 == undefined) return;
const json = await arg0.jsonValue();
consoleLogs.push(json)
consoleLogs.push(json);
});
await page.goto(`http://localhost:${fastify.server.address().port}`);
const content = await page.content();
......@@ -119,8 +130,9 @@ if (progression == 29) {
page.on('console', async consoleObj => {
const args = consoleObj.args();
const arg0 = args[0];
if (arg0 == undefined) return;
const json = await arg0.jsonValue();
consoleLogs.push(json)
consoleLogs.push(json);
});
await page.goto(`http://localhost:${fastify.server.address().port}`);
await page.evaluate('window.onload()');
......@@ -170,7 +182,7 @@ if (progression == 31) {
expect(trs.length).toStrictEqual(3);
for (let i = 0; i < trs.length; i++) {
const html = trs[i].innerHTML.trim().split('\n').map(line=>line.trim()).join('');
const level = data.levels[i];
const level = fakeData.levels[i];
expect(html).toStrictEqual(`<td>${level.length} lettres</td><td>${level.theme}</td><td>${''.repeat(level.difficulty)}</td><td><a>Démarrer</a></td>`);
}
});
......@@ -323,11 +335,13 @@ if (progression >= 37) {
const app = new ClientApp(game);
dom.reconfigure({url: 'http://localhost:3000/level/2'});
await app.main();
const content = document.querySelector("#level_description").innerHTML;
const content = (document.querySelector("#level_description").innerHTML || '')
+ (document.querySelector("#level_description").innerText || '');
expect(content).toStrictEqual('Sciences (6 lettres)');
dom.reconfigure({url: 'http://localhost:3000'});
await app.main();
const content2 = document.querySelector("#level_description").innerHTML;
const content2 = (document.querySelector("#level_description").innerHTML || '')
+ (document.querySelector("#level_description").innerText || '');
expect(content2).toStrictEqual('');
});
}
......@@ -437,7 +451,9 @@ if (progression >= 43) {
await app.main();
expect(spyFetch).toHaveBeenCalledTimes(1);
expect(spyFetch).toBeCalledWith('/api/level/2');
expect(document.querySelector("#level_description").innerHTML).toStrictEqual('Sciences (6 lettres)');
const content = (document.querySelector("#level_description").innerHTML || '')
+ (document.querySelector("#level_description").innerText || '');
expect(content).toStrictEqual('Sciences (6 lettres)');
});
}
......
export const data = {
"levels": [
{"id": 1, "length": 5, "theme": "Littérature", "difficulty": 3},
{"id": 2, "length": 6, "theme": "Sciences", "difficulty": 4},
{"id": 3, "length": 6, "theme": "Culture générale", "difficulty": 5},
{"id": 4, "length": 7, "theme": "Géographie", "difficulty": 5},
{"id": 5, "length": 6, "theme": "Fruits", "difficulty": 3},
{"id": 6, "length": 9, "theme": "Pâtisserie", "difficulty": 4},
{"id": 7, "length": 5, "theme": "Sports", "difficulty": 5},
{"id": 8, "length": 8, "theme": "Nature", "difficulty": 4}
],
"words": {
"1": "LIVRE",
"2": "SAVANT",
"3": "AFFLUX",
"4": "CASCADE",
"5": "CERISE",
"6": "CROISSANT",
"7": "KAYAK",
"8": "MONTAGNE"
}
};
\ No newline at end of file
export class Game {
constructor (data){
this.data = data;
}
levels(){
return this.data.levels;
}
level(id){
for (let level of this.data.levels) {
if (level.id === id) {
return level;
}
}
/*return undefined;*/
throw new Error("Niveau non trouvé")
}
word(id){
const word = this.data.words[id];
if(word !== undefined){
return word;
}
throw new Error("Mot non trouvé")
}
stringToArray(string){
let result = [];
for(let i = 0; i < string.length; i++){
result.push(string[i].toUpperCase());
}
return result;
}
stringToArray(string){
return string.split("").map(char => char.toUpperCase());
}
letters(id){
const word = this.word(id);
const letterArray = this.stringToArray(word);
return letterArray.sort();
}
computeLine(id, playedWord){
const word = this.word(id);
const result = [];
for(let i = 0; i < word.length; i++){
const playedLetter = i < playedWord.length ? playedWord[i].toUpperCase() : '_';
const letter = word[i].toUpperCase();
result.push({"letter" : playedLetter, "state" : playedLetter == letter});
}
return result;
}
}
import { data } from "./data.js";
import { Game } from "./game.js";
import { ServerApp } from "./server-app.js";
const app = new ServerApp();
const game = new Game(data);
const app = new ServerApp(game);
app.start(5000, true);
\ No newline at end of file
......@@ -4,9 +4,15 @@ import { fastifyStatic } from "@fastify/static";
export class ServerApp {
build(logEnabled) {
const fastify = new Fastify({logger: logEnabled})
fastify.register(fastifyStatic, { root: new URL('static', import.meta.url) });
fastify.setNotFoundHandler((request, reply) => this.sendIndex(reply));
const fastify = Fastify({ logger: logEnabled });
fastify.register(fastifyStatic, { root: new URL('./static', import.meta.url) });
fastify.get('/api/levels', (request, reply) => this.getLevels(request, reply));
fastify.get('/api/level/:id(^\\d+$)', (request, reply) => this.getLevel(request, reply));
fastify.get("/api/letters/:id(^\\d+$)", (request, reply) => this.getLetters(request, reply));
return fastify;
}
......@@ -21,4 +27,24 @@ export class ServerApp {
const stream = fs.createReadStream(new URL('static/index.html', import.meta.url));
reply.code(200).type('text/html').send(stream);
}
constructor(game) {
this.game = game;
}
getLevel(request, reply) {
const id = parseInt(request.params.id, 10); // Récupère l'ID depuis l'URL
const level = this.game.level(id); // Récupère les informations du niveau via l'objet game
if (level) {
reply.code(200).send(level); // Renvoie le niveau avec le statut 200
} else {
reply.code(404).send({ error: 'Niveau non trouvé' }); // Niveau introuvable
}
}
getLetters(request, reply) {
const id = parseInt(request.params.id, 10); // Récupère l'identifiant du niveau
const letters = this.game.letters(id); // Récupère les lettres du niveau via l'objet `game`
reply.code(200).send(letters); // Envoie les lettres en JSON avec un statut 200
}
}
export class ClientApp {
constructor(game) {
this.game = game;
}
async loadIndex() {
const content = document.querySelector("#content");
const levelDescription= document.querySelector("#level_description");
levelDescription.textContent = "";
content.innerHTML = `
<br>
<table class="table table-striped table-hover">
<thead>
<tr>
<th>Longueur</th>
<th>Thème</th>
<th>Difficulté</th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
`;
await this.addLevels();
}
async addLevels() {
const levels = await this.game.levels();
for (const level of levels) {
this.addLevel(level);
}
}
addLevel(level) {
const body = document.querySelector('tbody');
const tr = document.createElement('tr');
// TODO : ajouter les cellules à la ligne
const tdLength = document.createElement('td');
tdLength.textContent = `${level.length} lettres`;
tr.appendChild(tdLength);
const tdTheme = document.createElement('td');
tdTheme.textContent = level.theme;
tr.appendChild(tdTheme);
const tdDifficulty = document.createElement('td');
tdDifficulty.textContent = ''.repeat(level.difficulty);
//tdDifficulty.textContent = stars;
tr.appendChild(tdDifficulty);
const tdAction = document.createElement('td');
const link = document.createElement('a');
link.textContent = 'Démarrer';
link.href = `/level/${level.id}`;
tdAction.appendChild(link);
tr.appendChild(tdAction);
body.appendChild(tr);
}
async loadLevel(id) {
const level = await this.game.level(id); // Récupère les infos du niveau
const letters = await this.game.letters(id); // Récupère les lettres du niveau
const content = document.querySelector("#content");
const levelDescription = document.querySelector("#level_description");
levelDescription.textContent = `${level.theme} (${level.length} lettres)`;
content.innerHTML = `
<br>
<div class="col-4 offset-4">
<table class="table table-bordered text-center">
<tbody>
</tbody>
</table>
<div class="input-group mb-3">
<input type="text" class="form-control">
<button class="btn btn-outline-secondary">Proposer</button>
</div>
</div>`;
this.addLetters(letters); // Ajoute les lettres récupérées
const submitButton = document.querySelector("button");
submitButton.onclick = () => this.onSubmitWord(id);
}
addLetters(letters) {
const tbody = document.querySelector("tbody");
const tr = document.createElement("tr");
for (const letter of letters) {
const td = document.createElement("td");
td.innerHTML = letter;
td.classList.add("text-bg-primary");
tr.appendChild(td);
}
tbody.appendChild(tr);
}
addLine(line) {
const tbody = document.querySelector("tbody");
const tr = document.createElement("tr");
for (const cell of line){
const td = document.createElement("td");
td.innerHTML = cell.letter;
const classes= cell.state ? "text-bg-success" : "text-bg-danger";
td.classList.add(classes);
tr.appendChild(td);
}
tbody.appendChild(tr);
}
onSubmitWord(id) {
const input = document.querySelector("input");
const word = input.value;
const line = this.game.computeLine(id, word);
this.addLine(line);
input.value= "";
}
loadError(code, message) {
const content = document.querySelector("#content");
content.innerHTML = `
<div class="d-flex align-items-center justify-content-center vh-100">
<div class="text-center">
<h1 class="display-1 fw-bold">${code}</h1>
<p class="lead">${message}</p>
<a href="/" class="btn btn-primary">Retour à la liste des jeux</a>
</div>
</div>
`;
const levelDescription = document.querySelector("#level_description");
levelDescription.innerText = '';
}
async main() {
try {
const pathname = window.location.pathname;
if (pathname === '/') {
await this.loadIndex();
} else if (pathname.startsWith('/level/')) {
const lastIndex = pathname.lastIndexOf('/');
const id = parseInt(pathname.substring(lastIndex + 1));
await this.loadLevel(id);
} else {
this.loadError(404, 'Page non trouvée');
}
} catch (error) {
this.loadError(500, 'Erreur interne');
}
}
}
export class Game {
constructor (data){
this.data = data;
}
async levels() {
const response = await fetch('http://localhost:5000/api/levels');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
}
async level(id) {
const response = await fetch(`http://localhost:5000/api/level/${id}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json(); // Retourne les informations du niveau sous forme d'objet
}
word(id){
const word = this.data.words[id];
if(word !== undefined){
return word;
}
throw new Error("Mot non trouvé")
}
stringToArray(string){
let result = [];
for(let i = 0; i < string.length; i++){
result.push(string[i].toUpperCase());
}
return result;
}
stringToArray(string){
return string.split("").map(char => char.toUpperCase());
}
async letters(id) {
const response = await fetch(`http://localhost:5000/api/letters/${id}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
}
computeLine(id, playedWord){
const word = this.word(id);
const result = [];
for(let i = 0; i < word.length; i++){
const playedLetter = i < playedWord.length ? playedWord[i].toUpperCase() : '_';
const letter = word[i].toUpperCase();
result.push({"letter" : playedLetter, "state" : playedLetter == letter});
}
return result;
}
}
......@@ -6,6 +6,7 @@
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN"
crossorigin="anonymous">
<link rel="icon" href="/favicon.svg" />
<script type="module" src="/index.js"></script>
</head>
<body>
<div class="navbar navbar-dark bg-dark">
......
import { data } from "./data.js";
import { ClientApp } from "./client-app.js";
import { Game } from "./game.js";
const game = new Game(data);
const app = new ClientApp(game);
window.onload = () => app.main();
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment