From fc7069175fa5ece5e8720d4a123477f222fe6cb5 Mon Sep 17 00:00:00 2001
From: "alec.schmidt" <alec.schmidt@etu.hesge.ch>
Date: Mon, 12 Jun 2023 21:12:52 +0200
Subject: [PATCH] it is finished, anything more is just bugfixes and details
 changes

---
 API/src/socket.io/ServerIO.ts                 | 73 +++++++++++--------
 .../src/app/gameroom/gameroom.component.html  | 32 ++++++--
 .../src/app/gameroom/gameroom.component.ts    | 28 ++++++-
 frontend/src/app/services/socket.service.ts   | 18 +++++
 4 files changed, 114 insertions(+), 37 deletions(-)

diff --git a/API/src/socket.io/ServerIO.ts b/API/src/socket.io/ServerIO.ts
index 829fb6e..96d9901 100644
--- a/API/src/socket.io/ServerIO.ts
+++ b/API/src/socket.io/ServerIO.ts
@@ -12,6 +12,7 @@ class ServerIO extends IO.Server {
     private gameOngoing: boolean = false;
     private playerList: string[] = [];
     private questions : Question_t[] = [];
+    private scoreboard: { [username: string] : number; } = {}
 
     constructor(server: http.Server) {
         super(server, {
@@ -38,18 +39,15 @@ class ServerIO extends IO.Server {
             if (this.gameOngoing)
                 return socket.emit('Room Full');
 
-            const token = socket.handshake.query.Authorization;    
+            const token = socket.handshake.query.Authorization as string; 
 
-            var user: User_t = null;
-            jwt.verify(token, process.env.TOKEN_SECRET, (err:any, res:User_t) => {
-                // console.log(err);
-                if (err) return false;
-                user = res;
-            });
+            var user: User_t = this.decodeToken(token);
             
             logger.info(user.username + ` joined the game`);
             this.playerList.push(user.username);
             
+            this.scoreboard[user.username] = 0;
+
             socket.emit('Players Waiting', this.playerList.length)
             socket.broadcast.emit('Players Waiting', this.playerList.length);
 
@@ -58,19 +56,16 @@ class ServerIO extends IO.Server {
         })
 
         socket.on('Leave Room', _ => {
-            const token = socket.handshake.query.Authorization;
+            const token = socket.handshake.query.Authorization as string;
+            
+            var user = this.decodeToken(token);
+
+            var index: number = this.playerList.indexOf(user.username, 0);
             
-            var index: number;
-            var username: string;
-            jwt.verify(token, process.env.TOKEN_SECRET, (err:any, user:User_t) => {
-                if (err) return;
-                index = this.playerList.indexOf(user.username, 0);
-                username = user.username;
-            });
             
             if (index != -1) {
                 this.playerList.splice(index, 1);
-                logger.info(username + ` left the game`);
+                logger.info(user.username + ` left the game`);
             }
 
             socket.emit('Players Waiting', this.playerList.length)
@@ -79,32 +74,45 @@ class ServerIO extends IO.Server {
 
         socket.on('disconnect', _ => {
 
-            const token = socket.handshake.query.Authorization;
+            const token = socket.handshake.query.Authorization as string;
             
-            var index = -1;
-            var username: string;
-            jwt.verify(token, process.env.TOKEN_SECRET, (err:any, user:User_t) => {
-                if (err) return;
-                index = this.playerList.indexOf(user.username, 0); 
-                
-                username = user.username;
-            });
+            var user = this.decodeToken(token);
+            var index = this.playerList.indexOf(user.username, 0);
             
             logger.info(`Socket disconnected on ${ socket.client.conn.remoteAddress }`);
             if (index == -1)
                 return;
             
+            delete this.scoreboard[user.username]
             this.playerList.splice(index, 1);
-            logger.info(username + ` left the game`);
+            logger.info(user.username + ` left the game`);
             socket.emit('Players Waiting', this.playerList.length);
         })
 
         socket.on(`Answer`, answer => {
+            const answerTyped = answer as Answer_t;
+            const token = socket.handshake.query.Authorization as string;
 
+            const user = this.decodeToken(token);
 
+            if (answerTyped.correct)
+                this.scoreboard[user.username]++;
+            else
+                this.scoreboard[user.username] -= 2;
+
+            socket.emit("Points", this.scoreboard[user.username])
             this.sendQuestion();
         })
-    } 
+    }
+
+    decodeToken(token: string): User_t {
+        var userDecoded: User_t = undefined;
+        jwt.verify(token, process.env.TOKEN_SECRET, (err:any, user:User_t) => {
+            if (err) return userDecoded;
+            userDecoded = user;
+        });
+        return userDecoded;
+    }
 
     private async game() {
         this.gameOngoing = true;
@@ -123,7 +131,7 @@ class ServerIO extends IO.Server {
         if (this.questions.length == 0)
             return this.gameEnd()
 
-        console.log(this.questions)
+        console.log(this.scoreboard)
         
         let currentQuestion = this.questions.pop()
 
@@ -139,7 +147,14 @@ class ServerIO extends IO.Server {
     }
 
     gameEnd() {
-
+        logger.info(`Game ended, kicking out every players...`)
+        
+        this.emit("Game End", this.scoreboard);
+        this.playerList = [];
+        this.scoreboard = {};
+        
+        this.emit('Players Waiting', this.playerList.length)
+        this.gameOngoing = false;
     }
 
 }
diff --git a/frontend/src/app/gameroom/gameroom.component.html b/frontend/src/app/gameroom/gameroom.component.html
index fdb1511..2e0e432 100644
--- a/frontend/src/app/gameroom/gameroom.component.html
+++ b/frontend/src/app/gameroom/gameroom.component.html
@@ -1,20 +1,38 @@
 <div class="m-10">
-    <div *ngIf="!gameStart" class="bg-white flex flex-col items-center w-fit p-6 rounded-lg border-2 border-black">
+    <div *ngIf="!gameStart && !endGame" class="bg-white flex flex-col items-center w-fit p-6 rounded-lg border-2 border-black">
         <span class="w-fit">Player number : {{playerNumber}}/3</span>
         
         <button class="bg-white w-fit border-2 border-black rounded-lg px-2 hover:bg-gray-300 mt-2" *ngIf="!inRoom" (click)="joinRoom()">Join Room</button>
         <button class="bg-white w-fit border-2 border-black rounded-lg px-2 hover:bg-gray-300 mt-2" *ngIf="inRoom" (click)="leaveRoom()">Leave Room</button>
     </div>
-    <div *ngIf="gameStart">
-        {{question}}
 
-        <table>
-            <thead><th>Answers</th></thead>
+    <div *ngIf="gameStart && !endGame" class="bg-white flex flex-col w-fit p-6 rounded-lg border-2 border-black">
+        <span>Score : {{points}}</span>
+        <h1>{{question}}</h1>
+
+        <table class="text-left">
+            <thead class="border-b font-medium dark:border-neutral-500"><th class="px-6 py-4">Answers</th></thead>
+            <tbody>
+                <tr *ngFor="let answer of answers" class="border-b dark:border-neutral-500">
+                    <td><button (click)="sendAnswer(answer)" class="w-full hover:bg-gray-300">{{answer.text_answer}}</button></td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+
+    <div *ngIf="gameStart && endGame" class="bg-white flex flex-col w-fit p-6 rounded-lg border-2 border-black">
+        <table class="text-left">
+            <thead class="border-b font-medium dark:border-neutral-500">
+                <th class="py-4">Player</th>
+                <th class="py-4">Points</th>
+            </thead>
             <tbody>
-                <tr *ngFor="let answer of answers">
-                    <td><button (click)="sendAnswer(answer)">{{answer.text_answer}}</button></td>
+                <tr *ngFor="let score of scoreboard | keyvalue" class="border-b dark:border-neutral-500">
+                    <td>{{score.key}}</td>
+                    <td>{{score.value}}</td>
                 </tr>
             </tbody>
         </table>
+        <button class="bg-white w-fit border-2 border-black rounded-lg px-2 hover:bg-gray-300 mt-2" (click)="exitGame()">Nice</button>
     </div>
 </div>
\ No newline at end of file
diff --git a/frontend/src/app/gameroom/gameroom.component.ts b/frontend/src/app/gameroom/gameroom.component.ts
index 55190c4..67763b7 100644
--- a/frontend/src/app/gameroom/gameroom.component.ts
+++ b/frontend/src/app/gameroom/gameroom.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnDestroy, OnInit } from '@angular/core';
+import { Component, OnDestroy, OnInit, Pipe, PipeTransform } from '@angular/core';
 import { Socket } from 'ngx-socket-io';
 import { SocketService } from '../services/socket.service';
 import { QuestionsService } from '../services/questions.service';
@@ -17,6 +17,9 @@ export class GameroomComponent implements OnInit, OnDestroy {
   question: string = "";
   answers!: Answer[];
   inRoom: boolean = false;
+  endGame: boolean = false;
+  scoreboard: { [username: string] : number; } = {};
+  points!: number;
 
   constructor(
     private socket: SocketService) {}
@@ -37,6 +40,16 @@ export class GameroomComponent implements OnInit, OnDestroy {
     this.socket.answers.subscribe(answers => {
       this.answers = answers;
     })
+
+    this.socket.points.subscribe(points => {
+      this.points = points;
+    })
+
+    this.socket.scoreboard.subscribe(scoreboard => {
+      this.scoreboard = scoreboard;
+      if (this.gameStart)
+        this.endGame = true;
+    })
   }
   
   ngOnDestroy(): void {
@@ -57,4 +70,17 @@ export class GameroomComponent implements OnInit, OnDestroy {
     this.socket.sendAnswer(answer);
   }
 
+  exitGame(): void {
+    this.endGame = false;
+    this.gameStart = false;
+    this.inRoom = false;
+    this.socket.leaveRoom();
+  }
 }
+
+@Pipe({ name: 'keys',  pure: false })
+    export class KeysPipe implements PipeTransform {
+        transform(value: any, args: any[] = null): any {
+            return Object.keys(value)//.map(key => value[key]);
+        }
+    }
\ No newline at end of file
diff --git a/frontend/src/app/services/socket.service.ts b/frontend/src/app/services/socket.service.ts
index 42b7b6e..7d910e8 100644
--- a/frontend/src/app/services/socket.service.ts
+++ b/frontend/src/app/services/socket.service.ts
@@ -17,6 +17,8 @@ export class SocketService {
   private _gameStart = new BehaviorSubject<boolean>(false);
   private _currentQuestion = new BehaviorSubject<string>("");
   private _currentAnswers = new BehaviorSubject<Answer[]>([]);
+  private _points = new BehaviorSubject<number>(0);
+  private _scoreboard = new BehaviorSubject<{ [username: string] : number; }>({});
 
   constructor(
     private socket: Socket
@@ -43,6 +45,14 @@ export class SocketService {
     return this._currentAnswers.asObservable();
   }
 
+  get points() {
+    return this._points.asObservable();
+  }
+
+  get scoreboard() {
+    return this._scoreboard.asObservable();
+  }
+
   refreshSocketToken(): void {
     this.socket.ioSocket.io.opts.query = { Authorization: localStorage.getItem("token")};
   }
@@ -61,6 +71,14 @@ export class SocketService {
     this.socket.on("Game Start", ()=> {
       this._gameStart.next(true);
     })
+
+    this.socket.on("Points", points => {
+      this._points.next(points);
+    })
+
+    this.socket.on("Game End", scoreboard => {
+      this._scoreboard.next(scoreboard);
+    })
   }
 
   recievePlayerNumber(): void {
-- 
GitLab