Added card styles
This commit is contained in:
@@ -9,8 +9,13 @@ import org.springframework.web.servlet.view.RedirectView;
|
||||
|
||||
import com.bernard.nodecames.game.GameManager;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Controller
|
||||
public class HttpController {
|
||||
|
||||
GameManager gm;
|
||||
|
||||
@GetMapping("/")
|
||||
public String index() {
|
||||
@@ -24,7 +29,7 @@ public class HttpController {
|
||||
|
||||
@GetMapping("/create-room")
|
||||
public RedirectView createRoom() {
|
||||
UUID uuid = GameManager.newGrid();
|
||||
UUID uuid = gm.newGrid();
|
||||
return new RedirectView("/room/"+uuid.toString()+"/grid");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +1,56 @@
|
||||
package com.bernard.nodecames.frontend;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.handler.annotation.Header;
|
||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||
import org.springframework.messaging.handler.annotation.Payload;
|
||||
import org.springframework.messaging.handler.annotation.SendTo;
|
||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
|
||||
import com.bernard.nodecames.game.GameManager;
|
||||
import com.bernard.nodecames.model.Card;
|
||||
import com.bernard.nodecames.model.Grid;
|
||||
import com.bernard.nodecames.model.Card.Color;
|
||||
import com.bernard.nodecames.model.Grid.Phase;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.node.JsonNodeFactory;
|
||||
import tools.jackson.databind.node.ObjectNode;
|
||||
|
||||
@Controller
|
||||
@AllArgsConstructor
|
||||
public class WebSocketController {
|
||||
|
||||
private static final JsonNodeFactory jsn = JsonNodeFactory.instance;
|
||||
|
||||
@Autowired
|
||||
GameManager gm;
|
||||
private GameManager gm;
|
||||
private SimpMessagingTemplate template;
|
||||
|
||||
public void publishNewPhase(Grid g) {
|
||||
this.template.convertAndSend(
|
||||
"/topic/new-phase",
|
||||
g.getPhase().name().toLowerCase()
|
||||
);
|
||||
}
|
||||
public void publishCardUpdateToPlayer(Grid g, int cardIndex, char player) {
|
||||
Card c = g.getCards()[cardIndex];
|
||||
this.template.convertAndSend(
|
||||
"/topic/update-card/" + Character.toLowerCase(player),
|
||||
gm.cardData(c, player),
|
||||
Map.of("cardIndex", cardIndex)
|
||||
);
|
||||
}
|
||||
public void publishCardUpdate(Grid g, int cardIndex) {
|
||||
publishCardUpdateToPlayer(g, cardIndex, 'A');
|
||||
publishCardUpdateToPlayer(g, cardIndex, 'B');
|
||||
}
|
||||
|
||||
@GetMapping("/room/{id}/game/{player}")
|
||||
public Object grid(@PathVariable("id") String gridId, @PathVariable("player") String playerStr) {
|
||||
@@ -36,9 +62,9 @@ public class WebSocketController {
|
||||
else
|
||||
throw new IllegalArgumentException("Unknown player type");
|
||||
|
||||
Grid g = GameManager.findGrid(gridId);
|
||||
Grid g = gm.findGrid(gridId);
|
||||
|
||||
return new ResponseEntity<>(GameManager.gridData(g, player), HttpStatus.OK);
|
||||
return new ResponseEntity<>(gm.gridData(g, player), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@MessageMapping("submit-hint")
|
||||
@@ -47,10 +73,11 @@ public class WebSocketController {
|
||||
String hint = content.asObject().get("hint").stringValue();
|
||||
int wordCount = content.asObject().get("hintWordCount").intValue();
|
||||
|
||||
Grid g = GameManager.findGrid(roomId);
|
||||
Grid g = gm.findGrid(roomId);
|
||||
|
||||
gm.proposeHint(g, player.charAt(0), hint, wordCount);
|
||||
|
||||
content.asObject().set("player", jsn.stringNode(player));
|
||||
this.publishNewPhase(g);
|
||||
return content;
|
||||
}
|
||||
|
||||
@@ -59,17 +86,24 @@ public class WebSocketController {
|
||||
public JsonNode pointCard(@Header("room") String roomId, @Header("player") String player, @Payload JsonNode content) {
|
||||
int cardIndex = content.asObject().get("cardIndex").intValue();
|
||||
|
||||
Grid g = GameManager.findGrid(roomId);
|
||||
gm.pointCard(g, player.charAt(0), cardIndex);
|
||||
Grid g = gm.findGrid(roomId);
|
||||
Color c = 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);
|
||||
return content;
|
||||
}
|
||||
|
||||
@MessageMapping("end-guessing")
|
||||
@SendTo("/topic/end-guessing")
|
||||
public String endGuessing(@Header("room") String roomId, @Header("player") String player) {
|
||||
Grid g = GameManager.findGrid(roomId);
|
||||
public JsonNode endGuessing(@Header("room") String roomId, @Header("player") String player) {
|
||||
Grid g = gm.findGrid(roomId);
|
||||
gm.endGuessing(g, player.charAt(0));
|
||||
|
||||
return "";
|
||||
ObjectNode out = jsn.objectNode();
|
||||
out.set("player", jsn.stringNode(player));
|
||||
return out;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
package com.bernard.nodecames.game;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.bernard.nodecames.model.Card;
|
||||
@@ -27,48 +33,90 @@ public class GameManager {
|
||||
|
||||
private static final JsonNodeFactory jsn = JsonNodeFactory.instance;
|
||||
|
||||
//TODO Remove static, make something more Spring Boot-y
|
||||
private static Map<UUID, Grid> games = new HashMap<>();
|
||||
|
||||
public static JsonNode gridData(Grid g, char player) {
|
||||
@Value("classpath:dictionaries/fr.txt")
|
||||
Resource dictFr;
|
||||
|
||||
//TODO do Spring boot magic to only generate this once
|
||||
public List<String> allWords() {
|
||||
try (Scanner wordsScanner = new Scanner(dictFr.getInputStream())) {
|
||||
List<String> out = new ArrayList<>();
|
||||
while (wordsScanner.hasNextLine())
|
||||
out.add(wordsScanner.nextLine());
|
||||
return Collections.unmodifiableList(out);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException("Could not read internal dictionnary", e);
|
||||
}
|
||||
}
|
||||
|
||||
public String[] randomWords(int count) {
|
||||
List<String> allWords = allWords();
|
||||
//TODO seed the games
|
||||
Random r = new Random();
|
||||
if(count > allWords.size())
|
||||
throw new IllegalArgumentException("Not enough words in the dictionary");
|
||||
String[] out = new String[count];
|
||||
Set<Integer> already = new HashSet<>();
|
||||
int k;
|
||||
for(int i = 0; i<count; i++) {
|
||||
do {
|
||||
k = r.nextInt(allWords.size());
|
||||
} while (already.contains(k));
|
||||
out[i] = allWords.get(k);
|
||||
already.add(k);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
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.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++) {
|
||||
ObjectNode cardNode = jsn.objectNode();
|
||||
Card c = g.getCards()[i];
|
||||
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()));
|
||||
cardsNode.add(cardNode);
|
||||
}
|
||||
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()) {
|
||||
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;
|
||||
}
|
||||
eventsNode.add(geNode);
|
||||
}
|
||||
for(GameEvent ge : g.getGameEvents())
|
||||
eventsNode.add(eventData(g, ge));
|
||||
|
||||
ObjectNode currentHintNode = jsn.objectNode();
|
||||
if(g.getCurrentHint() != null) {
|
||||
@@ -89,15 +137,13 @@ public class GameManager {
|
||||
return out;
|
||||
}
|
||||
|
||||
public static Grid findGrid(String gridId) {
|
||||
public Grid findGrid(String gridId) {
|
||||
return games.get(UUID.fromString(gridId));
|
||||
}
|
||||
|
||||
public static UUID newGrid() {
|
||||
public UUID newGrid() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
String[] words = new String[25];
|
||||
for (int i = 0; i < words.length; i++)
|
||||
words[i] = "MotNumero"+Integer.toString(i);
|
||||
String[] words = randomWords(25);
|
||||
List<Card> cards = new ArrayList<>(25);
|
||||
int i = 0;
|
||||
cards.add(new Card(words[i++], Color.BLACK, Color.BLACK));
|
||||
@@ -141,7 +187,7 @@ public class GameManager {
|
||||
g.setCurrentGuessCount(0);
|
||||
}
|
||||
|
||||
public void 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)) ||
|
||||
((player == 'B') && (g.getPhase() == Grid.Phase.GUESSING_B)))) {
|
||||
throw new RuntimeException("This action is not allowed now");
|
||||
@@ -199,7 +245,7 @@ public class GameManager {
|
||||
g.setPhase(Grid.Phase.HINTING_B);
|
||||
g.newGameEvent(GameEvent.newEndGuessingEvent(false, player));
|
||||
}
|
||||
|
||||
return (player == 'A')?c.getColorB():c.getColorA();
|
||||
}
|
||||
|
||||
public void endGuessing(Grid g, char player) {
|
||||
|
||||
Reference in New Issue
Block a user