feat!(DevWeb):Add timer for games

/!\ Warning: Need to rebuild the DB
This commit is contained in:
Lucàs
2024-05-01 14:36:18 +02:00
parent d54de92ce9
commit 0741b5ce94
7 changed files with 112 additions and 41 deletions
+1
View File
@@ -22,6 +22,7 @@ CREATE TABLE IF NOT EXISTS game
nb_rounds INT NOT NULL, nb_rounds INT NOT NULL,
nb_colors INT NOT NULL, nb_colors INT NOT NULL,
nb_values_per_color INT NOT NULL, nb_values_per_color INT NOT NULL,
timer INT NOT NULL,
PRIMARY KEY (id) PRIMARY KEY (id)
); );
@@ -69,7 +69,7 @@ public class Game implements Serializable {
@Transient @Transient
private Deck deck; private Deck deck;
@Transient @Column(name = "timer")
private int timer; private int timer;
@Transient @Transient
@@ -90,6 +90,7 @@ public class Game implements Serializable {
public Game() { public Game() {
this.createdAt = new Date(); this.createdAt = new Date();
this.players = new ArrayList<>(); this.players = new ArrayList<>();
this.timer = 0;
} }
/** /**
@@ -4,5 +4,6 @@ public enum ClickChoice {
COLOR_VALUE, COLOR_VALUE,
COLOR, COLOR,
VALUE, VALUE,
NONE NONE,
TIMER_END
} }
@@ -16,7 +16,7 @@ public class SimpleGame {
this.id = game.getId().intValue(); this.id = game.getId().intValue();
this.players = new ArrayList<>(); this.players = new ArrayList<>();
for (Player p : playerArrayList) players.add(new SimplePlayer(p, game.getCurrentRound())); for (Player p : playerArrayList) players.add(new SimplePlayer(p, game.getCurrentRound()));
this.currentCard = game.getDeck().getCards().get(game.getCurrentRound()); this.currentCard = game.getDeck().getCards().get(game.getCurrentRound() % game.getDeck().getCards().size());
this.currentRound = game.getCurrentRound(); this.currentRound = game.getCurrentRound();
} }
@@ -21,7 +21,7 @@ public class SimplePlayer {
this.rightClickCount = player.getRightClickCount(); this.rightClickCount = player.getRightClickCount();
this.rapidClickCount = player.getRapidClickCount(); this.rapidClickCount = player.getRapidClickCount();
this.currentCard = player.getDeck().getCards().get(currentRound); this.currentCard = player.getDeck().getCards().get(currentRound % player.getDeck().getCards().size());
} }
public SimplePlayer(Player player) { public SimplePlayer(Player player) {
@@ -12,6 +12,8 @@ import jakarta.websocket.server.ServerEndpoint;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import uppa.project.bean.PlayerBean; import uppa.project.bean.PlayerBean;
import uppa.project.database.dao.DAO; import uppa.project.database.dao.DAO;
import uppa.project.database.dao.DAOException; import uppa.project.database.dao.DAOException;
@@ -27,19 +29,20 @@ import uppa.project.json.websocket.Message;
import uppa.project.json.websocket.SimpleGame; import uppa.project.json.websocket.SimpleGame;
import uppa.project.json.websocket.SimplePlayer; import uppa.project.json.websocket.SimplePlayer;
import uppa.project.json.websocket.SimpleUser; import uppa.project.json.websocket.SimpleUser;
import uppa.project.utils.GameProvider;
@ServerEndpoint(value = "/ws/game/{game_id}") @ServerEndpoint(value = "/ws/game/{game_id}")
public class GameWS { public class GameWS {
private static final HashMap<Game, ArrayList<Player>> games = new HashMap<>(); private static final HashMap<Game, ArrayList<Player>> games = new HashMap<>();
private static final HashMap<Game, Timer> timers = new HashMap<>();
Gson gson = new Gson(); Gson gson = new Gson();
private Game game; private Game game;
private Player player; private Player player;
@OnOpen @OnOpen
public void onOpen(Session session, @PathParam("game_id") String gameId) throws DAOException { public void onOpen(Session session, @PathParam("game_id") String gameId) throws DAOException {
this.game = GameProvider.getGame(Integer.parseInt(gameId)); DAO<Game> gameDAO = new Game_JPA_DAO_Factory().getDAOGame();
this.game = gameDAO.findById(Integer.parseInt(gameId));
if (!games.containsKey(game)) games.put(game, new ArrayList<>()); if (!games.containsKey(game)) games.put(game, new ArrayList<>());
} }
@@ -84,7 +87,18 @@ public class GameWS {
if (message.getType().equals("start")) { if (message.getType().equals("start")) {
game.setGameState(Game.GameState.STARTED); game.setGameState(Game.GameState.STARTED);
broadcast(new Message("start", gson.toJson(new SimpleGame(game, games.get(game)))).toJson()); broadcast(new Message("start", gson.toJson(new SimpleGame(game, games.get(game)))).toJson());
// TODO Start Timer
// TODO Start the timer
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// Broadcast the end of the game
broadcast(new Message("timerEnd", gson.toJson(new SimpleGame(game, games.get(game)))).toJson());
timer.cancel();
}
}, game.getTimer() * 1000L);
timers.put(game, timer);
} }
if (message.getType().equals("click")) { if (message.getType().equals("click")) {
@@ -151,6 +165,7 @@ public class GameWS {
player.setScore(playerScore - 1); player.setScore(playerScore - 1);
} }
} }
case TIMER_END -> {}
} }
} else { } else {
int nbSameCard = countSameCard(gameCard, games.get(game), game.getCurrentRound()); int nbSameCard = countSameCard(gameCard, games.get(game), game.getCurrentRound());
@@ -187,13 +202,14 @@ public class GameWS {
} }
} }
case NONE -> { case NONE -> {
if ((nbNone > nbSameCard) && (nbNone >= nbSameColor) && (nbNone > nbSameValue)){ if ((nbNone > nbSameCard) && (nbNone >= nbSameColor) && (nbNone > nbSameValue)) {
player.incrementRightClickCount(); player.incrementRightClickCount();
player.setScore(playerScore + 2); player.setScore(playerScore + 2);
} else { } else {
player.setScore(playerScore - 1); player.setScore(playerScore - 1);
} }
} }
case TIMER_END -> {}
} }
} }
@@ -205,6 +221,8 @@ public class GameWS {
// If all players have clicked // If all players have clicked
if (gameClickCount >= games.get(game).size()) { if (gameClickCount >= games.get(game).size()) {
// Stop the timer if it's running
timers.get(game).cancel();
// Reset the current click for all players // Reset the current click for all players
for (Player p : games.get(game)) p.setCurrentClick(null); for (Player p : games.get(game)) p.setCurrentClick(null);
@@ -223,7 +241,16 @@ public class GameWS {
// Check if the game is over // Check if the game is over
if (game.nextRound() || (second.getScore() == theoricWinner.getScore() && second.getRapidClickCount() == theoricWinner.getRapidClickCount())) { if (game.nextRound() || (second.getScore() == theoricWinner.getScore() && second.getRapidClickCount() == theoricWinner.getRapidClickCount())) {
broadcast(new Message("nextRound", gson.toJson(new SimpleGame(game, games.get(game)))).toJson()); broadcast(new Message("nextRound", gson.toJson(new SimpleGame(game, games.get(game)))).toJson());
// TODO Start Timer Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// Broadcast the end of the game
broadcast(new Message("timerEnd", gson.toJson(new SimpleGame(game, games.get(game)))).toJson());
timer.cancel();
}
}, game.getTimer() * 1000L);
timers.put(game, timer);
} else { } else {
theoricWinner.setWinner(); theoricWinner.setWinner();
@@ -231,11 +258,10 @@ public class GameWS {
em.getTransaction().begin(); em.getTransaction().begin();
for (Player p : games.get(game)) { for (Player p : games.get(game)) {
PlayerBean playerBean = new PlayerBean(p); PlayerBean playerBean = new PlayerBean(p);
if (playerBean.validate()) System.out.println("Player "+p.getUser().getUsername()+" sauvegardé en base de données"); if (playerBean.validate()) System.out.println("Player " + p.getUser().getUsername() + " sauvegardé en base de données");
else System.out.println(""); else System.out.println();
}; }
em.getTransaction().commit(); em.getTransaction().commit();
em.close();
// Broadcast the end of the game // Broadcast the end of the game
broadcast(new Message("end", gson.toJson(new SimpleGame(game, games.get(game)))).toJson()); broadcast(new Message("end", gson.toJson(new SimpleGame(game, games.get(game)))).toJson());
@@ -246,6 +272,7 @@ public class GameWS {
/** /**
* Retourne le nombre de joueurs avec une carte identique à celle du plateau * Retourne le nombre de joueurs avec une carte identique à celle du plateau
*
* @param gameCard carte du plateau * @param gameCard carte du plateau
* @param players liste des joueurs * @param players liste des joueurs
* @param currentRound manche courante * @param currentRound manche courante
@@ -256,7 +283,7 @@ public class GameWS {
for (Player player : players) { for (Player player : players) {
Card card = player.getDeck().getCards().get(currentRound); Card card = player.getDeck().getCards().get(currentRound);
if (gameCard.equals(card)) { if (gameCard.equals(card)) {
counter ++; counter++;
} }
} }
return counter; return counter;
@@ -264,6 +291,7 @@ public class GameWS {
/** /**
* Retourne le nombre de joueurs avec une carte avec seulement la couleur correspondante à celle du plateau * Retourne le nombre de joueurs avec une carte avec seulement la couleur correspondante à celle du plateau
*
* @param gameCard * @param gameCard
* @param players * @param players
* @param currentRound * @param currentRound
@@ -274,7 +302,7 @@ public class GameWS {
for (Player player : players) { for (Player player : players) {
Card card = player.getDeck().getCards().get(currentRound); Card card = player.getDeck().getCards().get(currentRound);
if (gameCard.getColor().equals(card.getColor()) && !gameCard.getValue().equals(card.getValue())) { if (gameCard.getColor().equals(card.getColor()) && !gameCard.getValue().equals(card.getValue())) {
counter ++; counter++;
} }
} }
return counter; return counter;
@@ -282,6 +310,7 @@ public class GameWS {
/** /**
* Retourne le nombre de joueurs avec une carte avec seulement la valeur correspondante à celle du plateau * Retourne le nombre de joueurs avec une carte avec seulement la valeur correspondante à celle du plateau
*
* @param gameCard carte du plateau * @param gameCard carte du plateau
* @param players liste des joueurs * @param players liste des joueurs
* @param currentRound manche courante * @param currentRound manche courante
@@ -292,7 +321,7 @@ public class GameWS {
for (Player player : players) { for (Player player : players) {
Card card = player.getDeck().getCards().get(currentRound); Card card = player.getDeck().getCards().get(currentRound);
if (gameCard.getValue().equals(card.getValue()) && !gameCard.getColor().equals(card.getColor())) { if (gameCard.getValue().equals(card.getValue()) && !gameCard.getColor().equals(card.getColor())) {
counter ++; counter++;
} }
} }
return counter; return counter;
@@ -300,6 +329,7 @@ public class GameWS {
/** /**
* Retourne le nombre de joueurs avec une carte totalement différente de celle du plateau * Retourne le nombre de joueurs avec une carte totalement différente de celle du plateau
*
* @param gameCard * @param gameCard
* @param players * @param players
* @param currentRound * @param currentRound
@@ -310,7 +340,7 @@ public class GameWS {
for (Player player : players) { for (Player player : players) {
Card card = player.getDeck().getCards().get(currentRound); Card card = player.getDeck().getCards().get(currentRound);
if (!gameCard.getColor().equals(card.getColor()) && !gameCard.getValue().equals(card.getValue())) { if (!gameCard.getColor().equals(card.getColor()) && !gameCard.getValue().equals(card.getValue())) {
counter ++; counter++;
} }
} }
return counter; return counter;
@@ -51,6 +51,7 @@
style="position: absolute; right: 0; z-index: 9999"> style="position: absolute; right: 0; z-index: 9999">
<div class="buttons is-flex-direction-column"> <div class="buttons is-flex-direction-column">
<p id="round" class="title has-text-white"></p> <p id="round" class="title has-text-white"></p>
<p id="timer" class="subtitle has-text-white"></p>
<button class="button is-fullwidth" data-value="COLOR_VALUE">Même couleur et valeur</button> <button class="button is-fullwidth" data-value="COLOR_VALUE">Même couleur et valeur</button>
<button class="button is-fullwidth" data-value="COLOR">Même couleur</button> <button class="button is-fullwidth" data-value="COLOR">Même couleur</button>
<button class="button is-fullwidth" data-value="VALUE">Même valeur</button> <button class="button is-fullwidth" data-value="VALUE">Même valeur</button>
@@ -212,6 +213,22 @@
import Card from "${pageContext.request.contextPath}/static/js/Card.js" import Card from "${pageContext.request.contextPath}/static/js/Card.js"
const choice = document.querySelector('#choice'); const choice = document.querySelector('#choice');
let havePlayed = false;
const timer = ${game.timer};
let remainingTime = timer;
let timerInterval;
// Display timer
document.querySelector('#timer').innerText = "Temps restant: " + remainingTime + "s";
const interval = () => {
remainingTime--;
document.querySelector('#timer').innerText = "Temps restant: " + remainingTime + "s";
if (remainingTime <= 0) clearInterval(timerInterval);
}
choice.querySelectorAll('button').forEach(button => { choice.querySelectorAll('button').forEach(button => {
button.addEventListener('click', () => { button.addEventListener('click', () => {
@@ -221,6 +238,8 @@
} }
wsgame.ws.send(JSON.stringify(message)); wsgame.ws.send(JSON.stringify(message));
havePlayed = true;
// Disable buttons // Disable buttons
choice.querySelectorAll('button').forEach(button => button.disabled = true); choice.querySelectorAll('button').forEach(button => button.disabled = true);
}); });
@@ -255,6 +274,8 @@
document.querySelector('#gameWaiting').style.display = 'none'; document.querySelector('#gameWaiting').style.display = 'none';
document.querySelector('#gameStarted').style.display = 'block'; document.querySelector('#gameStarted').style.display = 'block';
timerInterval = setInterval(interval, 1000);
const deck = document.querySelector('#deck'); // Column const deck = document.querySelector('#deck'); // Column
const myCard = document.querySelector('#myCard'); // Column const myCard = document.querySelector('#myCard'); // Column
const otherCards = document.querySelector('#otherCards'); // Columns const otherCards = document.querySelector('#otherCards'); // Columns
@@ -267,7 +288,7 @@
round.innerText = ""; round.innerText = "";
// Show current round // Show current round
round.innerText = "Manche " + (currentGame.currentRound+1) round.innerText = "Manche " + (currentGame.currentRound + 1)
// Show other player cards // Show other player cards
game.players game.players
@@ -296,9 +317,16 @@
wsgame.onMessage("updatePlayer", (p) => { wsgame.onMessage("updatePlayer", (p) => {
document.querySelector(".player-" + p.user.id + " .card-play").style.boxShadow = "inset 0px 0px 30px 10px orange"; document.querySelector(".player-" + p.user.id + " .card-play").style.boxShadow = "inset 0px 0px 30px 10px orange";
}) })
wsgame.onMessage("end", (game) => { wsgame.onMessage("timerEnd", (game) => {
window.location.href = "${pageContext.request.contextPath}/game-statistics?id=${game.id}&endGame=true"; if (!havePlayed) {
const message = {
type: "click",
data: "TIMER_END"
}
wsgame.ws.send(JSON.stringify(message));
}
}) })
wsgame.onMessage("nextRound", (game) => { wsgame.onMessage("nextRound", (game) => {
currentGame = game; currentGame = game;
@@ -311,12 +339,17 @@
const otherCards = document.querySelector('#otherCards'); // Columns const otherCards = document.querySelector('#otherCards'); // Columns
const round = document.querySelector('#round'); const round = document.querySelector('#round');
clearInterval(timerInterval);
remainingTime = timer;
document.querySelector('#timer').innerText = "Temps restant: " + remainingTime + "s";
timerInterval = setInterval(interval, 1000);
// Reset content // Reset content
deck.innerHTML = ""; deck.innerHTML = "";
myCard.innerHTML = ""; myCard.innerHTML = "";
otherCards.innerHTML = ""; otherCards.innerHTML = "";
round.innerText = ""; round.innerText = "";
havePlayed = false;
choice.querySelectorAll('button').forEach(button => button.disabled = false); choice.querySelectorAll('button').forEach(button => button.disabled = false);
// Show the current round // Show the current round
@@ -347,6 +380,11 @@
deck.innerHTML = deckCard.render(); deck.innerHTML = deckCard.render();
}) })
wsgame.onMessage("end", (game) => {
clearInterval(timerInterval);
window.location.href = "${pageContext.request.contextPath}/game-statistics?id=${game.id}&endGame=true";
})
// Close handling // Close handling
wsgame.onClose(() => console.log("Disconnected from the server (GameWS)")); wsgame.onClose(() => console.log("Disconnected from the server (GameWS)"));