Remade game logic, added sudden death
This commit is contained in:
@@ -7,7 +7,6 @@ import org.springframework.http.ResponseEntity;
|
|||||||
import org.springframework.messaging.handler.annotation.Header;
|
import org.springframework.messaging.handler.annotation.Header;
|
||||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||||
import org.springframework.messaging.handler.annotation.Payload;
|
import org.springframework.messaging.handler.annotation.Payload;
|
||||||
import org.springframework.messaging.handler.annotation.SendTo;
|
|
||||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@@ -15,17 +14,14 @@ import org.springframework.web.bind.annotation.PathVariable;
|
|||||||
|
|
||||||
import com.bernard.nodecames.game.GameManager;
|
import com.bernard.nodecames.game.GameManager;
|
||||||
import com.bernard.nodecames.model.Card;
|
import com.bernard.nodecames.model.Card;
|
||||||
|
import com.bernard.nodecames.model.GameEvent;
|
||||||
import com.bernard.nodecames.model.Grid;
|
import com.bernard.nodecames.model.Grid;
|
||||||
import com.bernard.nodecames.model.Card.Color;
|
|
||||||
import com.bernard.nodecames.model.Grid.Phase;
|
import com.bernard.nodecames.model.Grid.Phase;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import tools.jackson.databind.JsonNode;
|
import tools.jackson.databind.JsonNode;
|
||||||
import tools.jackson.databind.node.JsonNodeFactory;
|
import tools.jackson.databind.node.JsonNodeFactory;
|
||||||
import tools.jackson.databind.node.ObjectNode;
|
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
@AllArgsConstructor
|
|
||||||
public class WebSocketController {
|
public class WebSocketController {
|
||||||
|
|
||||||
private static final JsonNodeFactory jsn = JsonNodeFactory.instance;
|
private static final JsonNodeFactory jsn = JsonNodeFactory.instance;
|
||||||
@@ -33,12 +29,25 @@ public class WebSocketController {
|
|||||||
private GameManager gm;
|
private GameManager gm;
|
||||||
private SimpMessagingTemplate template;
|
private SimpMessagingTemplate template;
|
||||||
|
|
||||||
public void publishNewPhase(Grid g) {
|
public WebSocketController(GameManager gm, SimpMessagingTemplate template) {
|
||||||
this.template.convertAndSend(
|
this.gm = gm;
|
||||||
"/topic/new-phase",
|
this.template = template;
|
||||||
g.getPhase().name().toLowerCase()
|
gm.setWsc(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onNewEvent(Grid g, GameEvent ge) {
|
||||||
|
this.template.convertAndSend("/topic/new-event",
|
||||||
|
gm.eventData(g, ge)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void onNewPhase(Grid g, Phase p) {
|
||||||
|
this.template.convertAndSend(
|
||||||
|
"/topic/new-phase",
|
||||||
|
gm.phaseData(g.getPhase())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public void publishCardUpdateToPlayer(Grid g, int cardIndex, char player) {
|
public void publishCardUpdateToPlayer(Grid g, int cardIndex, char player) {
|
||||||
Card c = g.getCards()[cardIndex];
|
Card c = g.getCards()[cardIndex];
|
||||||
this.template.convertAndSend(
|
this.template.convertAndSend(
|
||||||
@@ -68,42 +77,27 @@ public class WebSocketController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@MessageMapping("submit-hint")
|
@MessageMapping("submit-hint")
|
||||||
@SendTo("/topic/submit-hint")
|
public void submitHint(@Header("room") String roomId, @Header("player") String player, @Payload JsonNode content) {
|
||||||
public JsonNode submitHint(@Header("room") String roomId, @Header("player") String player, @Payload JsonNode content) {
|
|
||||||
String hint = content.asObject().get("hint").stringValue();
|
String hint = content.asObject().get("hint").stringValue();
|
||||||
int wordCount = content.asObject().get("hintWordCount").intValue();
|
int wordCount = content.asObject().get("hintWordCount").intValue();
|
||||||
|
|
||||||
Grid g = gm.findGrid(roomId);
|
Grid g = gm.findGrid(roomId);
|
||||||
|
|
||||||
gm.proposeHint(g, player.charAt(0), hint, wordCount);
|
gm.proposeHint(g, player.charAt(0), hint, wordCount);
|
||||||
content.asObject().set("player", jsn.stringNode(player));
|
|
||||||
this.publishNewPhase(g);
|
|
||||||
return content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@MessageMapping("point-card")
|
@MessageMapping("point-card")
|
||||||
@SendTo("/topic/point-card")
|
public void pointCard(@Header("room") String roomId, @Header("player") String player, @Payload JsonNode content) {
|
||||||
public JsonNode pointCard(@Header("room") String roomId, @Header("player") String player, @Payload JsonNode content) {
|
|
||||||
int cardIndex = content.asObject().get("cardIndex").intValue();
|
int cardIndex = content.asObject().get("cardIndex").intValue();
|
||||||
|
|
||||||
Grid g = gm.findGrid(roomId);
|
Grid g = gm.findGrid(roomId);
|
||||||
Color c = gm.pointCard(g, player.charAt(0), cardIndex);
|
gm.pointCard(g, player.charAt(0), cardIndex);
|
||||||
content.asObject().set("color", jsn.stringNode(c.name().toLowerCase()));
|
|
||||||
content.asObject().set("player", jsn.stringNode(player));
|
|
||||||
if(g.getPhase() != Phase.GUESSING_A && g.getPhase() != Phase.GUESSING_B)
|
|
||||||
publishNewPhase(g);
|
|
||||||
publishCardUpdate(g, cardIndex);
|
publishCardUpdate(g, cardIndex);
|
||||||
return content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@MessageMapping("end-guessing")
|
@MessageMapping("end-guessing")
|
||||||
@SendTo("/topic/end-guessing")
|
public void endGuessing(@Header("room") String roomId, @Header("player") String player) {
|
||||||
public JsonNode endGuessing(@Header("room") String roomId, @Header("player") String player) {
|
|
||||||
Grid g = gm.findGrid(roomId);
|
Grid g = gm.findGrid(roomId);
|
||||||
gm.endGuessing(g, player.charAt(0));
|
gm.endGuessing(g, player.charAt(0));
|
||||||
|
|
||||||
ObjectNode out = jsn.objectNode();
|
|
||||||
out.set("player", jsn.stringNode(player));
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import java.util.HashMap;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -17,12 +18,15 @@ import org.springframework.beans.factory.annotation.Value;
|
|||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import com.bernard.nodecames.frontend.WebSocketController;
|
||||||
import com.bernard.nodecames.model.Card;
|
import com.bernard.nodecames.model.Card;
|
||||||
|
import com.bernard.nodecames.model.Card.Color;
|
||||||
import com.bernard.nodecames.model.GameEvent;
|
import com.bernard.nodecames.model.GameEvent;
|
||||||
import com.bernard.nodecames.model.Grid;
|
import com.bernard.nodecames.model.Grid;
|
||||||
|
import com.bernard.nodecames.model.Grid.Phase;
|
||||||
import com.bernard.nodecames.model.Hint;
|
import com.bernard.nodecames.model.Hint;
|
||||||
import com.bernard.nodecames.model.Card.Color;
|
|
||||||
|
|
||||||
|
import lombok.Setter;
|
||||||
import tools.jackson.databind.JsonNode;
|
import tools.jackson.databind.JsonNode;
|
||||||
import tools.jackson.databind.node.ArrayNode;
|
import tools.jackson.databind.node.ArrayNode;
|
||||||
import tools.jackson.databind.node.JsonNodeFactory;
|
import tools.jackson.databind.node.JsonNodeFactory;
|
||||||
@@ -33,12 +37,30 @@ public class GameManager {
|
|||||||
|
|
||||||
private static final JsonNodeFactory jsn = JsonNodeFactory.instance;
|
private static final JsonNodeFactory jsn = JsonNodeFactory.instance;
|
||||||
|
|
||||||
|
public static final int MAX_HINT_COUNT = 9;
|
||||||
|
|
||||||
//TODO Remove static, make something more Spring Boot-y
|
//TODO Remove static, make something more Spring Boot-y
|
||||||
private static Map<UUID, Grid> games = new HashMap<>();
|
private static Map<UUID, Grid> games = new HashMap<>();
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
WebSocketController wsc;
|
||||||
|
|
||||||
@Value("classpath:dictionaries/fr.txt")
|
@Value("classpath:dictionaries/fr.txt")
|
||||||
Resource dictFr;
|
Resource dictFr;
|
||||||
|
|
||||||
|
private void newGameEvent(Grid g, GameEvent ge) {
|
||||||
|
g.newGameEvent(ge);
|
||||||
|
wsc.onNewEvent(g, ge);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPhase(Grid g, Phase phase) {
|
||||||
|
g.setPhase(phase);
|
||||||
|
if(!phase.isAnyoneGuessing()) {
|
||||||
|
g.setCurrentHint(null);
|
||||||
|
}
|
||||||
|
wsc.onNewPhase(g, phase);
|
||||||
|
}
|
||||||
|
|
||||||
//TODO do Spring boot magic to only generate this once
|
//TODO do Spring boot magic to only generate this once
|
||||||
public List<String> allWords() {
|
public List<String> allWords() {
|
||||||
try (Scanner wordsScanner = new Scanner(dictFr.getInputStream())) {
|
try (Scanner wordsScanner = new Scanner(dictFr.getInputStream())) {
|
||||||
@@ -70,71 +92,8 @@ public class GameManager {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JsonNode cardData(Card c, char player) {
|
private char other(char player) {
|
||||||
ObjectNode cardNode = jsn.objectNode();
|
return (player=='A')?'B':'A';
|
||||||
cardNode.set("word", jsn.stringNode(c.getWord()));
|
|
||||||
cardNode.set("color", jsn.stringNode((player=='A'?c.getColorA():c.getColorB()).name().toLowerCase()));
|
|
||||||
if((player=='A' && c.isRevealedA()) || (player=='B' && c.isRevealedB()))
|
|
||||||
cardNode.set("otherColor", jsn.stringNode((player=='A'?c.getColorB():c.getColorA()).name().toLowerCase()));
|
|
||||||
cardNode.set("revealed-a", jsn.booleanNode(c.isRevealedA()));
|
|
||||||
cardNode.set("revealed-b", jsn.booleanNode(c.isRevealedB()));
|
|
||||||
return cardNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonNode eventData(Grid g, GameEvent ge) {
|
|
||||||
ObjectNode geNode = jsn.objectNode();
|
|
||||||
geNode.set("type", jsn.stringNode(ge.getType().name().toLowerCase()));
|
|
||||||
geNode.set("issuer", jsn.stringNode(Character.toString(ge.getIssuer())));
|
|
||||||
switch (ge.getType()) {
|
|
||||||
case GameEvent.Type.HINT:
|
|
||||||
Hint hint = (Hint)ge.getData();
|
|
||||||
geNode.set("word", jsn.stringNode(hint.getWord()));
|
|
||||||
geNode.set("wordCount", jsn.numberNode(hint.getWordCount()));
|
|
||||||
break;
|
|
||||||
case GameEvent.Type.GUESS:
|
|
||||||
Card c = (Card)ge.getData();
|
|
||||||
Integer pos = IntStream.range(0, g.getCardCount())
|
|
||||||
.filter(i -> c == g.getCards()[i])
|
|
||||||
.findFirst()
|
|
||||||
.getAsInt();
|
|
||||||
geNode.set("card-index", jsn.numberNode(pos));
|
|
||||||
break;
|
|
||||||
case GameEvent.Type.END_GUESSING:
|
|
||||||
geNode.set("manual", jsn.booleanNode((Boolean)ge.getData()));
|
|
||||||
break;
|
|
||||||
case GameEvent.Type.START_GAME:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return geNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonNode gridData(Grid g, char player) {
|
|
||||||
|
|
||||||
ArrayNode cardsNode = jsn.arrayNode(g.getCardCount());
|
|
||||||
for (int i = 0; i < g.getCardCount(); i++)
|
|
||||||
cardsNode.add(cardData(g.getCards()[i], player));
|
|
||||||
|
|
||||||
ArrayNode eventsNode = jsn.arrayNode(g.getGameEvents().size());
|
|
||||||
for(GameEvent ge : g.getGameEvents())
|
|
||||||
eventsNode.add(eventData(g, ge));
|
|
||||||
|
|
||||||
ObjectNode currentHintNode = jsn.objectNode();
|
|
||||||
if(g.getCurrentHint() != null) {
|
|
||||||
currentHintNode.set("word", jsn.stringNode(g.getCurrentHint().getWord()));
|
|
||||||
currentHintNode.set("wordCount", jsn.numberNode(g.getCurrentHint().getWordCount()));
|
|
||||||
}
|
|
||||||
|
|
||||||
ObjectNode out = jsn.objectNode();
|
|
||||||
out.set("cards", cardsNode);
|
|
||||||
out.set("phase", jsn.stringNode(g.getPhase().name().toLowerCase()));
|
|
||||||
out.set("events", eventsNode);
|
|
||||||
if(g.getCurrentHint() != null)
|
|
||||||
out.set("current-hint", currentHintNode);
|
|
||||||
out.set("current-guess-count", jsn.numberNode(g.getCurrentGuessCount()));
|
|
||||||
out.set("used-hints", jsn.numberNode(g.getUsedHints()));
|
|
||||||
out.set("used-whites", jsn.numberNode(g.getUsedWhites()));
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Grid findGrid(String gridId) {
|
public Grid findGrid(String gridId) {
|
||||||
@@ -169,27 +128,159 @@ public class GameManager {
|
|||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* JSON ACCESSORS *
|
||||||
|
**********************************/
|
||||||
|
|
||||||
|
public JsonNode cardData(Card c, char player) {
|
||||||
|
ObjectNode cardNode = jsn.objectNode();
|
||||||
|
cardNode.set("word", jsn.stringNode(c.getWord()));
|
||||||
|
cardNode.set("color", jsn.stringNode((player=='A'?c.getColorA():c.getColorB()).name().toLowerCase()));
|
||||||
|
if((player=='A' && c.isColorBPublic()) || (player=='B' && c.isColorAPublic()))
|
||||||
|
cardNode.set("otherColor", jsn.stringNode((player=='A'?c.getColorB():c.getColorA()).name().toLowerCase()));
|
||||||
|
cardNode.set("revealed-a", jsn.booleanNode(c.isColorBPublic()));
|
||||||
|
cardNode.set("revealed-b", jsn.booleanNode(c.isColorAPublic()));
|
||||||
|
return cardNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonNode eventData(Grid g, GameEvent ge) {
|
||||||
|
ObjectNode geNode = jsn.objectNode();
|
||||||
|
geNode.set("type", jsn.stringNode(ge.getType().name().toLowerCase()));
|
||||||
|
geNode.set("issuer", jsn.stringNode(Character.toString(ge.getIssuer())));
|
||||||
|
switch (ge.getType()) {
|
||||||
|
case GameEvent.Type.HINT:
|
||||||
|
Hint hint = (Hint)ge.getData();
|
||||||
|
geNode.set("word", jsn.stringNode(hint.getWord()));
|
||||||
|
geNode.set("wordCount", jsn.numberNode(hint.getWordCount()));
|
||||||
|
break;
|
||||||
|
case GameEvent.Type.GUESS:
|
||||||
|
Card c = (Card)ge.getData();
|
||||||
|
Integer pos = IntStream.range(0, g.getCardCount())
|
||||||
|
.filter(i -> c == g.getCards()[i])
|
||||||
|
.findFirst()
|
||||||
|
.getAsInt();
|
||||||
|
geNode.set("card-index", jsn.numberNode(pos));
|
||||||
|
geNode.set("color", jsn.stringNode(((ge.getIssuer()=='A')?c.getColorB():c.getColorA()).name().toLowerCase()));
|
||||||
|
break;
|
||||||
|
case GameEvent.Type.END_GUESSING:
|
||||||
|
geNode.set("manual", jsn.booleanNode((Boolean)ge.getData()));
|
||||||
|
break;
|
||||||
|
case GameEvent.Type.GAME_END:
|
||||||
|
geNode.set("win", jsn.booleanNode((Boolean)ge.getData()));
|
||||||
|
break;
|
||||||
|
case GameEvent.Type.SUDDEN_DEATH:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return geNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonNode phaseData(Phase p) {
|
||||||
|
ObjectNode out = jsn.objectNode();
|
||||||
|
out.set("a-guessing", jsn.booleanNode(p.isAGuessing()));
|
||||||
|
out.set("b-guessing", jsn.booleanNode(p.isBGuessing()));
|
||||||
|
out.set("a-hinting", jsn.booleanNode(p.isAHinting()));
|
||||||
|
out.set("b-hinting", jsn.booleanNode(p.isBHinting()));
|
||||||
|
out.set("sudden-death", jsn.booleanNode(p.isSuddenDeath()));
|
||||||
|
out.set("game-ended", jsn.booleanNode(p.isGameEnded()));
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsonNode gridData(Grid g, char player) {
|
||||||
|
|
||||||
|
ArrayNode cardsNode = jsn.arrayNode(g.getCardCount());
|
||||||
|
for (int i = 0; i < g.getCardCount(); i++)
|
||||||
|
cardsNode.add(cardData(g.getCards()[i], player));
|
||||||
|
|
||||||
|
ArrayNode eventsNode = jsn.arrayNode(g.getGameEvents().size());
|
||||||
|
for(GameEvent ge : g.getGameEvents())
|
||||||
|
eventsNode.add(eventData(g, ge));
|
||||||
|
|
||||||
|
ObjectNode currentHintNode = jsn.objectNode();
|
||||||
|
if(g.getCurrentHint() != null) {
|
||||||
|
currentHintNode.set("word", jsn.stringNode(g.getCurrentHint().getWord()));
|
||||||
|
currentHintNode.set("wordCount", jsn.numberNode(g.getCurrentHint().getWordCount()));
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectNode out = jsn.objectNode();
|
||||||
|
out.set("cards", cardsNode);
|
||||||
|
out.set("phase", phaseData(g.getPhase()));
|
||||||
|
out.set("events", eventsNode);
|
||||||
|
if(g.getCurrentHint() != null)
|
||||||
|
out.set("current-hint", currentHintNode);
|
||||||
|
out.set("current-guess-count", jsn.numberNode(g.getCurrentGuessCount()));
|
||||||
|
out.set("used-hints", jsn.numberNode(g.getUsedHints()));
|
||||||
|
out.set("used-whites", jsn.numberNode(g.getUsedWhites()));
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*################################*
|
||||||
|
* GAME LOGIC *
|
||||||
|
*################################*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
@returns true iff all green cards of this player have been revealed either side
|
||||||
|
*/
|
||||||
|
public boolean allGreenRevealed(Grid g, char player) {
|
||||||
|
for(Card c : g.getCards()) {
|
||||||
|
if (c.getColor(player) == Color.GREEN && !c.isColorPublic(player) &&
|
||||||
|
!(c.getColor(other(player)) == Color.GREEN && c.isColorPublic(other(player))))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* GAME ACTIONS *
|
||||||
|
**********************************/
|
||||||
|
private void endGame(Grid g, boolean win) {
|
||||||
|
g.setWon(Optional.of(win));
|
||||||
|
setPhase(g, Phase.gameEnded());
|
||||||
|
newGameEvent(g, GameEvent.newGameEndEvent(win));
|
||||||
|
}
|
||||||
|
|
||||||
public void proposeHint(Grid g, char player, String hint, int wordCount) {
|
public void proposeHint(Grid g, char player, String hint, int wordCount) {
|
||||||
if (!(((player == 'A') && (g.getPhase() == Grid.Phase.HINTING_A)) ||
|
if (!g.getPhase().isHinting(player)) {
|
||||||
((player == 'B') && (g.getPhase() == Grid.Phase.HINTING_B)) ||
|
|
||||||
g.getPhase() == Grid.Phase.HINTING_ANY)) {
|
|
||||||
throw new RuntimeException("This action is not allowed now");
|
throw new RuntimeException("This action is not allowed now");
|
||||||
}
|
}
|
||||||
|
|
||||||
Hint h = new Hint(hint, wordCount);
|
Hint h = new Hint(hint, wordCount);
|
||||||
g.incrementHintCount();
|
g.incrementHintCount();
|
||||||
g.newGameEvent(GameEvent.newHintEvent(h, player));
|
|
||||||
if (player == 'A')
|
|
||||||
g.setPhase(Grid.Phase.GUESSING_B);
|
|
||||||
else
|
|
||||||
g.setPhase(Grid.Phase.GUESSING_A);
|
|
||||||
g.setCurrentHint(h);
|
g.setCurrentHint(h);
|
||||||
g.setCurrentGuessCount(0);
|
g.setCurrentGuessCount(0);
|
||||||
|
newGameEvent(g, GameEvent.newHintEvent(h, player));
|
||||||
|
setPhase(g, Phase.guessing(other(player)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Sets the phase of the grid when player ends its guessing round.
|
||||||
|
@param g Must neither be ended neither be in a sudden death
|
||||||
|
*/
|
||||||
|
private void endGuessingRound(Grid g, char player) {
|
||||||
|
// We're done with this round of guesses
|
||||||
|
if(g.getUsedHints() >= MAX_HINT_COUNT) {
|
||||||
|
// We're entering sudden death
|
||||||
|
newGameEvent(g, GameEvent.newSuddenDeath());
|
||||||
|
if(allGreenRevealed(g, player)) {
|
||||||
|
// If all my greens are revealed, i'm the only one to guess
|
||||||
|
setPhase(g, Phase.suddenDeathOnly(player));
|
||||||
|
} else {
|
||||||
|
// Else, we are both guessing
|
||||||
|
setPhase(g, Phase.suddenDeathBoth());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Next regular hinting round
|
||||||
|
if(allGreenRevealed(g, player)) {
|
||||||
|
// I can't hint anymore
|
||||||
|
setPhase(g, Phase.hinting(other(player)));
|
||||||
|
} else {
|
||||||
|
setPhase(g, Phase.hinting(player));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Card.Color pointCard(Grid g, char player, int cardIndex) {
|
public Card.Color pointCard(Grid g, char player, int cardIndex) {
|
||||||
if (!(((player == 'A') && (g.getPhase() == Grid.Phase.GUESSING_A)) ||
|
if (!g.getPhase().isGuessing(player)) {
|
||||||
((player == 'B') && (g.getPhase() == Grid.Phase.GUESSING_B)))) {
|
|
||||||
throw new RuntimeException("This action is not allowed now");
|
throw new RuntimeException("This action is not allowed now");
|
||||||
}
|
}
|
||||||
if (cardIndex<0 || cardIndex>g.getCardCount()) {
|
if (cardIndex<0 || cardIndex>g.getCardCount()) {
|
||||||
@@ -197,69 +288,52 @@ public class GameManager {
|
|||||||
}
|
}
|
||||||
Card c = g.getCards()[cardIndex];
|
Card c = g.getCards()[cardIndex];
|
||||||
|
|
||||||
boolean endedGuessing = false;
|
if(c.isColorPublic(other(player)) || (c.getColor(player) == Card.Color.GREEN && c.isColorPublic(player)))
|
||||||
|
throw new RuntimeException("Card has already been revealed");
|
||||||
|
c.setColorPublic(other(player), true);
|
||||||
|
Card.Color guessedColor = c.getColor(other(player));
|
||||||
|
|
||||||
if (player == 'A') {
|
newGameEvent(g, GameEvent.newGuessEvent(c, player));
|
||||||
if (c.isRevealedA() || (c.isRevealedB() && c.getColorA() == Card.Color.GREEN)) {
|
|
||||||
throw new RuntimeException("Card has already been revealed");
|
|
||||||
}
|
|
||||||
c.setRevealedA(true);
|
|
||||||
switch(c.getColorB()) {
|
|
||||||
case Card.Color.GREEN:
|
|
||||||
break;
|
|
||||||
case Card.Color.WHITE:
|
|
||||||
g.incrementWhiteCount();
|
|
||||||
endedGuessing = true;
|
|
||||||
break;
|
|
||||||
case Card.Color.BLACK:
|
|
||||||
endedGuessing = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (c.isRevealedB() || (c.isRevealedA() && c.getColorB() == Card.Color.GREEN)) {
|
|
||||||
throw new RuntimeException("Card has already been revealed");
|
|
||||||
}
|
|
||||||
c.setRevealedB(true);
|
|
||||||
switch(c.getColorA()) {
|
|
||||||
case Card.Color.GREEN:
|
|
||||||
break;
|
|
||||||
case Card.Color.WHITE:
|
|
||||||
g.incrementWhiteCount();
|
|
||||||
endedGuessing = true;
|
|
||||||
break;
|
|
||||||
case Card.Color.BLACK:
|
|
||||||
endedGuessing = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g.newGameEvent(GameEvent.newGuessEvent(c, player));
|
|
||||||
g.incrementCurrentGuessCount();
|
g.incrementCurrentGuessCount();
|
||||||
if (!g.getCurrentHint().canStillGuess(g.getCurrentGuessCount()))
|
if(guessedColor == Color.BLACK)
|
||||||
endedGuessing = true;
|
endGame(g, false);
|
||||||
|
else if (g.getPhase().isSuddenDeath() && guessedColor == Color.WHITE)
|
||||||
if(endedGuessing) {
|
endGame(g, false);
|
||||||
g.setCurrentHint(null);
|
else if (allGreenRevealed(g, other(player)) && guessedColor == Color.GREEN) {
|
||||||
if (player == 'A')
|
// i.e. i made my last guess
|
||||||
g.setPhase(Grid.Phase.HINTING_A);
|
if (allGreenRevealed(g, player)) {
|
||||||
else
|
endGame(g, true);
|
||||||
g.setPhase(Grid.Phase.HINTING_B);
|
} else if (g.getPhase().isSuddenDeath()) {
|
||||||
g.newGameEvent(GameEvent.newEndGuessingEvent(false, player));
|
// Sudden death with only the other
|
||||||
|
setPhase(g, Phase.suddenDeathOnly(other(player)));
|
||||||
|
} else {
|
||||||
|
endGuessingRound(g, player);
|
||||||
}
|
}
|
||||||
return (player == 'A')?c.getColorB():c.getColorA();
|
} else if (!allGreenRevealed(g, other(player)) && guessedColor == Color.GREEN) {
|
||||||
|
// There is still cards i should find
|
||||||
|
if (!g.getPhase().isSuddenDeath() && !g.getCurrentHint().canStillGuess(g.getCurrentGuessCount())) {
|
||||||
|
// We're done with this round of guesses
|
||||||
|
endGuessingRound(g, player);
|
||||||
|
} else {
|
||||||
|
// I continue guessing cards in this round
|
||||||
|
}
|
||||||
|
} else if (guessedColor == Color.WHITE && !g.getPhase().isSuddenDeath()){
|
||||||
|
endGuessingRound(g, player);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("This should logically never happen");
|
||||||
|
}
|
||||||
|
if(!g.getPhase().isAnyoneGuessing())
|
||||||
|
// It means this pick ended the guessing turn
|
||||||
|
newGameEvent(g, GameEvent.newEndGuessingEvent(false, player));
|
||||||
|
return guessedColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endGuessing(Grid g, char player) {
|
public void endGuessing(Grid g, char player) {
|
||||||
if (!(((player == 'A') && (g.getPhase() == Grid.Phase.GUESSING_A)) ||
|
if (!g.getPhase().isGuessing(player)) {
|
||||||
((player == 'B') && (g.getPhase() == Grid.Phase.GUESSING_B)))) {
|
|
||||||
throw new RuntimeException("This action is not allowed now");
|
throw new RuntimeException("This action is not allowed now");
|
||||||
}
|
}
|
||||||
|
endGuessingRound(g, player);
|
||||||
g.setCurrentHint(null);
|
newGameEvent(g, GameEvent.newEndGuessingEvent(true, player));
|
||||||
if (player == 'A')
|
|
||||||
g.setPhase(Grid.Phase.HINTING_B);
|
|
||||||
else
|
|
||||||
g.setPhase(Grid.Phase.HINTING_A);
|
|
||||||
g.newGameEvent(GameEvent.newEndGuessingEvent(true, player));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,33 @@ public class Card {
|
|||||||
|
|
||||||
Color colorA;
|
Color colorA;
|
||||||
Color colorB;
|
Color colorB;
|
||||||
// revealedA is wether A knows B's color
|
boolean colorAPublic;
|
||||||
boolean revealedA;
|
boolean colorBPublic;
|
||||||
boolean revealedB;
|
|
||||||
|
|
||||||
public Card(String word, Color colorA, Color colorB) {
|
public Card(String word, Color colorA, Color colorB) {
|
||||||
this(word, colorA, colorB, false, false);
|
this(word, colorA, colorB, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Color getColor(char player) {
|
||||||
|
if(player == 'A') return this.getColorA();
|
||||||
|
else return this.getColorB();
|
||||||
|
}
|
||||||
|
public boolean isColorPublic(char player) {
|
||||||
|
if(player == 'A') return this.isColorAPublic();
|
||||||
|
else return this.isColorBPublic();
|
||||||
|
}
|
||||||
|
public void setColorPublic(char player, boolean colorPublic) {
|
||||||
|
if(player == 'A') this.setColorAPublic(colorPublic);
|
||||||
|
else this.setColorBPublic(colorPublic);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format("%s [%s%s(%s%s)]", getWord(),
|
||||||
|
getColorA().name().charAt(0), getColorB().name().charAt(0),
|
||||||
|
isColorAPublic()?'O':'X', isColorBPublic()?'O':'X');
|
||||||
|
}
|
||||||
|
|
||||||
public enum Color {
|
public enum Color {
|
||||||
GREEN,
|
GREEN,
|
||||||
WHITE,
|
WHITE,
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package com.bernard.nodecames.model;
|
package com.bernard.nodecames.model;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.GeneratedValue;
|
import jakarta.persistence.GeneratedValue;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
|
|||||||
@@ -28,8 +28,11 @@ public class GameEvent {
|
|||||||
public static GameEvent newEndGuessingEvent(boolean manual, char issuer) {
|
public static GameEvent newEndGuessingEvent(boolean manual, char issuer) {
|
||||||
return new GameEvent(Type.END_GUESSING, manual, issuer);
|
return new GameEvent(Type.END_GUESSING, manual, issuer);
|
||||||
}
|
}
|
||||||
public static GameEvent newStartGameEvent() {
|
public static GameEvent newGameEndEvent(boolean won) {
|
||||||
return new GameEvent(Type.START_GAME, null, '_');
|
return new GameEvent(Type.GAME_END, won, '_');
|
||||||
|
}
|
||||||
|
public static GameEvent newSuddenDeath() {
|
||||||
|
return new GameEvent(Type.SUDDEN_DEATH, Object.class, '_');
|
||||||
}
|
}
|
||||||
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@@ -37,7 +40,8 @@ public class GameEvent {
|
|||||||
HINT(Hint.class),
|
HINT(Hint.class),
|
||||||
GUESS(Card.class),
|
GUESS(Card.class),
|
||||||
END_GUESSING(Boolean.class),
|
END_GUESSING(Boolean.class),
|
||||||
START_GAME(Object.class);
|
GAME_END(Boolean.class),
|
||||||
|
SUDDEN_DEATH(Object.class);
|
||||||
|
|
||||||
Class<?> dataType;
|
Class<?> dataType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ package com.bernard.nodecames.model;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.GeneratedValue;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@@ -29,9 +28,10 @@ public class Grid {
|
|||||||
int usedWhites;
|
int usedWhites;
|
||||||
|
|
||||||
Phase phase;
|
Phase phase;
|
||||||
|
Optional<Boolean> won;
|
||||||
|
|
||||||
public Grid(String name, Card[] cards) {
|
public Grid(String name, Card[] cards) {
|
||||||
this(name, cards, new ArrayList<>(), null, 0, 0, 0, Phase.HINTING_ANY);
|
this(name, cards, new ArrayList<>(), null, 0, 0, 0, Phase.bothHinting(), Optional.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void incrementHintCount() {
|
public void incrementHintCount() {
|
||||||
@@ -50,12 +50,59 @@ public class Grid {
|
|||||||
return this.getCards().length;
|
return this.getCards().length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Phase {
|
@EqualsAndHashCode
|
||||||
HINTING_ANY,
|
@Getter
|
||||||
HINTING_A,
|
public static class Phase {
|
||||||
HINTING_B,
|
private boolean aHinting;
|
||||||
GUESSING_A,
|
private boolean bHinting;
|
||||||
GUESSING_B;
|
private boolean aGuessing;
|
||||||
|
private boolean bGuessing;
|
||||||
|
private boolean suddenDeath;
|
||||||
|
|
||||||
|
boolean gameEnded;
|
||||||
|
|
||||||
|
private Phase(boolean aHinting,
|
||||||
|
boolean bHinting,
|
||||||
|
boolean aGuessing,
|
||||||
|
boolean bGuessing,
|
||||||
|
boolean suddenDeath,
|
||||||
|
boolean gameEnded) {
|
||||||
|
this.aHinting = aHinting;
|
||||||
|
this.bHinting = bHinting;
|
||||||
|
this.aGuessing = aGuessing;
|
||||||
|
this.bGuessing = bGuessing;
|
||||||
|
this.suddenDeath = suddenDeath;
|
||||||
|
this.gameEnded = gameEnded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHinting(char player) {
|
||||||
|
return (player == 'A')?this.isAHinting():this.isBHinting();
|
||||||
|
}
|
||||||
|
public boolean isGuessing(char player) {
|
||||||
|
return (player == 'A')?this.isAGuessing():this.isBGuessing();
|
||||||
|
}
|
||||||
|
public boolean isAnyoneGuessing() {
|
||||||
|
return this.isAGuessing() || this.isBGuessing();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Phase bothHinting() {
|
||||||
|
return new Phase(true, true, false, false, false, false);
|
||||||
|
}
|
||||||
|
public static Phase hinting(char player) {
|
||||||
|
return new Phase((player == 'A'), (player == 'B'), false, false, false, false);
|
||||||
|
}
|
||||||
|
public static Phase guessing(char player) {
|
||||||
|
return new Phase(false, false, (player == 'A'), (player == 'B'), false, false);
|
||||||
|
}
|
||||||
|
public static Phase suddenDeathBoth() {
|
||||||
|
return new Phase(false, false, true, true, true, false);
|
||||||
|
}
|
||||||
|
public static Phase suddenDeathOnly(char player) {
|
||||||
|
return new Phase(false, false, player == 'A', player == 'B', true, false);
|
||||||
|
}
|
||||||
|
public static Phase gameEnded() {
|
||||||
|
return new Phase(false,false,false,false,false,true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,36 +12,34 @@ function getRoomId() {
|
|||||||
return res[1]
|
return res[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update html to match state
|
||||||
|
*/
|
||||||
function updatePhase(phase) {
|
function updatePhase(phase) {
|
||||||
if(phase == "hinting_any" || (phase == "hinting_a" && player == 'A') || (phase == "hinting_b" && player == 'B')) {
|
p = player.toLowerCase()
|
||||||
// Hinting
|
o = (player=='A')?'b':'a'
|
||||||
$('.card-button').css('visibility', 'hidden')
|
if(phase[p+'-guessing']) {
|
||||||
$('#hint-text').hide()
|
|
||||||
$('#submit-hint').show()
|
|
||||||
$('#other-playing').hide()
|
|
||||||
$('#end-guessing').hide()
|
|
||||||
} else if ((phase == "hinting_b" && player == 'A') || (phase == "hinting_a" && player == 'B')) {
|
|
||||||
// Wait for the other one
|
|
||||||
$('.card-button').css('visibility', 'hidden')
|
|
||||||
$('#hint-text').hide()
|
|
||||||
$('#submit-hint').hide()
|
|
||||||
$('#other-playing').show()
|
|
||||||
$('#end-guessing').hide()
|
|
||||||
} else if ((phase == "guessing_a" && player == 'B') || (phase == "guessing_b" && player == 'A')) {
|
|
||||||
// Wait for the other one
|
|
||||||
$('.card-button').css('visibility', 'hidden')
|
|
||||||
$('#hint-text').show()
|
|
||||||
$('#submit-hint').hide()
|
|
||||||
$('#other-playing').show()
|
|
||||||
$('#end-guessing').hide()
|
|
||||||
} else if ((phase == "guessing_a" && player == 'A') || (phase == "guessing_b" && player == 'B')) {
|
|
||||||
// Guessing
|
|
||||||
$('.card-button').css('visibility', 'visible')
|
$('.card-button').css('visibility', 'visible')
|
||||||
$('.card-button.untouchable').css('visibility', 'hidden')
|
$('.card-button.untouchable').css('visibility', 'hidden')
|
||||||
|
$('#end-guessing-button').show()
|
||||||
|
} else {
|
||||||
|
$('.card-button').css('visibility', 'hidden')
|
||||||
|
$('#end-guessing-button').hide()
|
||||||
|
}
|
||||||
|
if(phase[p+'-guessing'] || phase[o+'-guessing']) {
|
||||||
$('#hint-text').show()
|
$('#hint-text').show()
|
||||||
|
} else {
|
||||||
|
$('#hint-text').hide()
|
||||||
|
}
|
||||||
|
if(phase[p+'-hinting']) {
|
||||||
|
$('#submit-hint').show()
|
||||||
|
} else {
|
||||||
$('#submit-hint').hide()
|
$('#submit-hint').hide()
|
||||||
|
}
|
||||||
|
if(!phase[p+'-guessing'] & !phase[p+'-hinting']) {
|
||||||
|
$('#other-playing').show()
|
||||||
|
} else {
|
||||||
$('#other-playing').hide()
|
$('#other-playing').hide()
|
||||||
$('#end-guessing').show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,6 +47,20 @@ function setHint(hint, wordCount) {
|
|||||||
$('#hint-text').text(hint+" in "+wordCount)
|
$('#hint-text').text(hint+" in "+wordCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createCard(i) {
|
||||||
|
html = `
|
||||||
|
<li class="card ${cards[i].color}" id="card-${i}">
|
||||||
|
<span class="card-word">${cards[i].word}</span><br/>
|
||||||
|
<div class="card-bottom-bar">
|
||||||
|
<div id="card-${i}-a-public">A</div>
|
||||||
|
<button class="card-button" id="card-${i}-button">Toucher</button>
|
||||||
|
<div id="card-${i}-b-public">B</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
`
|
||||||
|
$('#cards-list').append($(html))
|
||||||
|
$(`#card-${i}-button`).on('click', pointCard)
|
||||||
|
}
|
||||||
function updateCard(i) {
|
function updateCard(i) {
|
||||||
card = cards[i]
|
card = cards[i]
|
||||||
if(card['revealed-a']) {
|
if(card['revealed-a']) {
|
||||||
@@ -76,26 +88,102 @@ function updateCard(i) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addHintEvent(issuer, hint, hintWordCount) {
|
||||||
|
$("#event-log").append($(`
|
||||||
|
<li>
|
||||||
|
${issuer} proposed "${hint}" in ${hintWordCount} word(s)
|
||||||
|
</li>
|
||||||
|
`))
|
||||||
|
}
|
||||||
|
|
||||||
|
function addPointEvent(issuer, cardIndex, color) {
|
||||||
|
$("#event-log").append($(`
|
||||||
|
<li>
|
||||||
|
${issuer} pointed card ${cards[cardIndex].word} (${color})
|
||||||
|
</li>
|
||||||
|
`))
|
||||||
|
}
|
||||||
|
|
||||||
|
function addEndGuessingEvent(issuer, manual) {
|
||||||
|
if(manual) {
|
||||||
|
$("#event-log").append($(`
|
||||||
|
<li>
|
||||||
|
${issuer} ended guessing
|
||||||
|
</li>
|
||||||
|
`))
|
||||||
|
} else {
|
||||||
|
$("#event-log").append($(`
|
||||||
|
<li>
|
||||||
|
${issuer} can't guess anymore
|
||||||
|
</li>
|
||||||
|
`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function addSuddenDeathEvent() {
|
||||||
|
$("#event-log").append($(`
|
||||||
|
<li>
|
||||||
|
Starting sudden death
|
||||||
|
</li>
|
||||||
|
`))
|
||||||
|
}
|
||||||
|
function addEndGameEvent(issuer, won) {
|
||||||
|
if(won) {
|
||||||
|
$("#event-log").append($(`
|
||||||
|
<li>
|
||||||
|
You won the game !
|
||||||
|
</li>
|
||||||
|
`))
|
||||||
|
} else {
|
||||||
|
$("#event-log").append($(`
|
||||||
|
<li>
|
||||||
|
You lost the game !
|
||||||
|
</li>
|
||||||
|
`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addEvent(e) {
|
||||||
|
switch(e.type) {
|
||||||
|
case "hint":
|
||||||
|
addHintEvent(e.issuer, e.word, e.wordCount)
|
||||||
|
setHint(e.word, e.wordCount)
|
||||||
|
break
|
||||||
|
case "guess":
|
||||||
|
addPointEvent(e.issuer, e['card-index'], e.color)
|
||||||
|
break
|
||||||
|
case "end_guessing":
|
||||||
|
addEndGuessingEvent(e.issuer, e.manual)
|
||||||
|
break
|
||||||
|
case "game_end":
|
||||||
|
addEndGameEvent(e.issuer, e.win)
|
||||||
|
break
|
||||||
|
case "sudden_death":
|
||||||
|
addSuddenDeathEvent()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Listeners
|
||||||
|
*/
|
||||||
|
|
||||||
function initGame(data) {
|
function initGame(data) {
|
||||||
cards = data['cards']
|
cards = data['cards']
|
||||||
$('#cards-list').empty()
|
$('#cards-list').empty()
|
||||||
for(var i = 0; i<cards.length; i++) {
|
for(var i = 0; i<cards.length; i++) {
|
||||||
html = `
|
createCard(i)
|
||||||
<li class="card ${cards[i].color}" id="card-${i}">
|
|
||||||
<span class="card-word">${cards[i].word}</span><br/>
|
|
||||||
<div class="card-bottom-bar">
|
|
||||||
<div id="card-${i}-a-public">A</div>
|
|
||||||
<button class="card-button" id="card-${i}-button">Toucher</button>
|
|
||||||
<div id="card-${i}-b-public">B</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
`
|
|
||||||
$('#cards-list').append($(html))
|
|
||||||
$(`#card-${i}-button`).on('click', pointCard)
|
|
||||||
updateCard(i)
|
updateCard(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePhase(data['phase'])
|
updatePhase(data['phase'])
|
||||||
|
events = data.events
|
||||||
|
for(var i = 0; i<events.length; i++) {
|
||||||
|
e = events[i]
|
||||||
|
addEvent(e)
|
||||||
|
}
|
||||||
|
if(data['current-hint']) {
|
||||||
|
setHint(data['current-hint'].word, data['current-hint'].wordCount)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectPlayer(e) {
|
function selectPlayer(e) {
|
||||||
@@ -117,10 +205,8 @@ function selectPlayer(e) {
|
|||||||
|
|
||||||
socket = Stomp.over(new SockJS('/socket'));
|
socket = Stomp.over(new SockJS('/socket'));
|
||||||
socket.connect({}, function (frame) {
|
socket.connect({}, function (frame) {
|
||||||
socket.subscribe('/topic/submit-hint', onSubmitHint);
|
|
||||||
socket.subscribe('/topic/point-card', onPointCard);
|
|
||||||
socket.subscribe('/topic/end-guessing', onEndGuessing);
|
|
||||||
socket.subscribe('/topic/new-phase', onNewPhase);
|
socket.subscribe('/topic/new-phase', onNewPhase);
|
||||||
|
socket.subscribe('/topic/new-event', onNewEvent);
|
||||||
socket.subscribe('/topic/update-card/' + player.toLowerCase(), onUpdateCard);
|
socket.subscribe('/topic/update-card/' + player.toLowerCase(), onUpdateCard);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -142,34 +228,13 @@ function pointCard(e) {
|
|||||||
function endGuessing(e) {
|
function endGuessing(e) {
|
||||||
socket.send('/app/end-guessing', wsHeaders, "")
|
socket.send('/app/end-guessing', wsHeaders, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSubmitHint(m) {
|
|
||||||
data = JSON.parse(m.body)
|
|
||||||
setHint(data['hint'], data['hintWordCount'])
|
|
||||||
$("#event-log").append($(`
|
|
||||||
<li>
|
|
||||||
${data.player} proposed "${data['hint']}" in ${data['hintWordCount']} word(s)
|
|
||||||
</li>
|
|
||||||
`))
|
|
||||||
}
|
|
||||||
function onPointCard(m) {
|
|
||||||
data = JSON.parse(m.body)
|
|
||||||
i = data['cardIndex']
|
|
||||||
$("#event-log").append($(`
|
|
||||||
<li>
|
|
||||||
${data.player} pointed card ${cards[i].word} (${data.color})
|
|
||||||
</li>
|
|
||||||
`))
|
|
||||||
}
|
|
||||||
function onEndGuessing(m) {
|
|
||||||
$("#event-log").append($(`
|
|
||||||
<li>
|
|
||||||
Ended guessing
|
|
||||||
</li>
|
|
||||||
`))
|
|
||||||
}
|
|
||||||
function onNewPhase(m) {
|
function onNewPhase(m) {
|
||||||
updatePhase(m.body)
|
phase = JSON.parse(m.body)
|
||||||
|
updatePhase(phase)
|
||||||
|
}
|
||||||
|
function onNewEvent(m) {
|
||||||
|
e = JSON.parse(m.body)
|
||||||
|
addEvent(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onUpdateCard(m) {
|
function onUpdateCard(m) {
|
||||||
|
|||||||
Reference in New Issue
Block a user