First layout of the game
This commit is contained in:
@@ -1,13 +1,30 @@
|
||||
package com.bernard.nodecames;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
|
||||
import com.bernard.nodecames.game.GameManager;
|
||||
|
||||
@Controller
|
||||
public class HttpController {
|
||||
|
||||
@GetMapping("/")
|
||||
public String index() {
|
||||
return "index.html";
|
||||
}
|
||||
@GetMapping("/")
|
||||
public String index() {
|
||||
return "index.html";
|
||||
}
|
||||
|
||||
@GetMapping("/room/{id}/grid")
|
||||
public String grid(@PathVariable("id") String id) {
|
||||
return "grid";
|
||||
}
|
||||
|
||||
@GetMapping("/create-room")
|
||||
public RedirectView createRoom() {
|
||||
UUID uuid = GameManager.newGrid();
|
||||
return new RedirectView("/room/"+uuid.toString()+"/grid");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.bernard.nodecames.frontend;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;
|
||||
import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
public class WebSocketConfiguration implements WebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Bean
|
||||
public ServletServerContainerFactoryBean createWebSocketContainer() {
|
||||
ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
|
||||
container.setMaxTextMessageBufferSize(8192);
|
||||
container.setMaxBinaryMessageBufferSize(8192);
|
||||
return container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/socket").withSockJS();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry config) {
|
||||
// STOMP messages whose destination header begins with /app are routed to
|
||||
// @MessageMapping methods in @Controller classes
|
||||
config.setApplicationDestinationPrefixes("/app");
|
||||
// Use the built-in message broker for subscriptions and broadcasting and
|
||||
// route messages whose destination header begins with /topic or /queue to the broker
|
||||
config.enableSimpleBroker("/topic");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureWebSocketTransport(WebSocketTransportRegistration registry) {
|
||||
registry.setMessageSizeLimit(4 * 8192);
|
||||
registry.setTimeToFirstMessage(30000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.bernard.nodecames.frontend;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.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.Grid;
|
||||
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.node.JsonNodeFactory;
|
||||
|
||||
@Controller
|
||||
public class WebSocketController {
|
||||
|
||||
private static final JsonNodeFactory jsn = JsonNodeFactory.instance;
|
||||
|
||||
@Autowired
|
||||
GameManager gm;
|
||||
|
||||
@GetMapping("/room/{id}/game/{player}")
|
||||
public Object grid(@PathVariable("id") String gridId, @PathVariable("player") String playerStr) {
|
||||
char player;
|
||||
if(playerStr.equals("player-a"))
|
||||
player = 'A';
|
||||
else if (playerStr.equals("player-b"))
|
||||
player = 'B';
|
||||
else
|
||||
throw new IllegalArgumentException("Unknown player type");
|
||||
|
||||
Grid g = GameManager.findGrid(gridId);
|
||||
|
||||
return new ResponseEntity<>(GameManager.gridData(g, player), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@MessageMapping("submit-hint")
|
||||
@SendTo("/topic/submit-hint")
|
||||
public JsonNode submitHint(@Header("room") String roomId, @Header("player") String player, @Payload JsonNode content) {
|
||||
String hint = content.asObject().get("hint").stringValue();
|
||||
int wordCount = content.asObject().get("hintWordCount").intValue();
|
||||
|
||||
Grid g = GameManager.findGrid(roomId);
|
||||
|
||||
gm.proposeHint(g, player.charAt(0), hint, wordCount);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
@MessageMapping("point-card")
|
||||
@SendTo("/topic/point-card")
|
||||
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);
|
||||
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);
|
||||
gm.endGuessing(g, player.charAt(0));
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
package com.bernard.nodecames.game;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.bernard.nodecames.model.Card;
|
||||
import com.bernard.nodecames.model.GameEvent;
|
||||
import com.bernard.nodecames.model.Grid;
|
||||
import com.bernard.nodecames.model.Hint;
|
||||
import com.bernard.nodecames.model.Card.Color;
|
||||
|
||||
import tools.jackson.databind.JsonNode;
|
||||
import tools.jackson.databind.node.ArrayNode;
|
||||
import tools.jackson.databind.node.JsonNodeFactory;
|
||||
import tools.jackson.databind.node.ObjectNode;
|
||||
|
||||
@Service
|
||||
public class GameManager {
|
||||
|
||||
private static final JsonNodeFactory jsn = JsonNodeFactory.instance;
|
||||
|
||||
private static Map<UUID, Grid> games = new HashMap<>();
|
||||
|
||||
public static 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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 static Grid findGrid(String gridId) {
|
||||
return games.get(UUID.fromString(gridId));
|
||||
}
|
||||
|
||||
public static 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);
|
||||
List<Card> cards = new ArrayList<>(25);
|
||||
int i = 0;
|
||||
cards.add(new Card(words[i++], Color.BLACK, Color.BLACK));
|
||||
for (;i < 4; i++)
|
||||
cards.add(new Card(words[i], Color.GREEN, Color.GREEN));
|
||||
for (;i < 9; i++)
|
||||
cards.add(new Card(words[i], Color.WHITE, Color.GREEN));
|
||||
for (;i < 14; i++)
|
||||
cards.add(new Card(words[i], Color.GREEN, Color.WHITE));
|
||||
cards.add(new Card(words[i++], Color.GREEN, Color.BLACK));
|
||||
cards.add(new Card(words[i++], Color.BLACK, Color.GREEN));
|
||||
cards.add(new Card(words[i++], Color.WHITE, Color.BLACK));
|
||||
cards.add(new Card(words[i++], Color.BLACK, Color.WHITE));
|
||||
for (;i < 25; i++)
|
||||
cards.add(new Card(words[i], Color.WHITE, Color.WHITE));
|
||||
|
||||
Collections.shuffle(cards);
|
||||
|
||||
Grid g = new Grid(uuid.toString(), (Card[])cards.toArray(new Card[cards.size()]));
|
||||
|
||||
games.put(uuid, g);
|
||||
|
||||
return uuid;
|
||||
}
|
||||
|
||||
public void proposeHint(Grid g, char player, String hint, int wordCount) {
|
||||
if (!(((player == 'A') && (g.getPhase() == Grid.Phase.HINTING_A)) ||
|
||||
((player == 'B') && (g.getPhase() == Grid.Phase.HINTING_B)) ||
|
||||
g.getPhase() == Grid.Phase.HINTING_ANY)) {
|
||||
throw new RuntimeException("This action is not allowed now");
|
||||
}
|
||||
|
||||
Hint h = new Hint(hint, wordCount);
|
||||
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.setCurrentGuessCount(0);
|
||||
}
|
||||
|
||||
public void 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");
|
||||
}
|
||||
if (cardIndex<0 || cardIndex>g.getCardCount()) {
|
||||
throw new IllegalArgumentException("The given card index is invalid");
|
||||
}
|
||||
Card c = g.getCards()[cardIndex];
|
||||
|
||||
boolean endedGuessing = false;
|
||||
|
||||
if (player == 'A') {
|
||||
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();
|
||||
if (!g.getCurrentHint().canStillGuess(g.getCurrentGuessCount()))
|
||||
endedGuessing = true;
|
||||
|
||||
if(endedGuessing) {
|
||||
g.setCurrentHint(null);
|
||||
if (player == 'A')
|
||||
g.setPhase(Grid.Phase.HINTING_A);
|
||||
else
|
||||
g.setPhase(Grid.Phase.HINTING_B);
|
||||
g.newGameEvent(GameEvent.newEndGuessingEvent(false, player));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void endGuessing(Grid g, char player) {
|
||||
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");
|
||||
}
|
||||
|
||||
g.setCurrentHint(null);
|
||||
if (player == 'A')
|
||||
g.setPhase(Grid.Phase.HINTING_B);
|
||||
else
|
||||
g.setPhase(Grid.Phase.HINTING_A);
|
||||
g.newGameEvent(GameEvent.newEndGuessingEvent(true, player));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.bernard.nodecames.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class Card {
|
||||
|
||||
String word;
|
||||
|
||||
Color colorA;
|
||||
Color colorB;
|
||||
// revealedA is wether A knows B's color
|
||||
boolean revealedA;
|
||||
boolean revealedB;
|
||||
|
||||
public Card(String word, Color colorA, Color colorB) {
|
||||
this(word, colorA, colorB, false, false);
|
||||
}
|
||||
|
||||
public enum Color {
|
||||
GREEN,
|
||||
WHITE,
|
||||
BLACK;
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,25 @@
|
||||
package com.bernard.nodecames.model;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class Game {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
String name;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.bernard.nodecames.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class GameEvent {
|
||||
|
||||
Type type;
|
||||
|
||||
Object data;
|
||||
|
||||
// 'A' for player A, 'B' for player B, '_' for none
|
||||
char issuer;
|
||||
|
||||
private GameEvent(Type type, Object data, char issuer){
|
||||
this.data = data;
|
||||
this.issuer = issuer;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static GameEvent newHintEvent(Hint h, char issuer) {
|
||||
return new GameEvent(Type.HINT, h, issuer);
|
||||
}
|
||||
public static GameEvent newGuessEvent(Card c, char issuer) {
|
||||
return new GameEvent(Type.GUESS, c, issuer);
|
||||
}
|
||||
public static GameEvent newEndGuessingEvent(boolean manual, char issuer) {
|
||||
return new GameEvent(Type.END_GUESSING, manual, issuer);
|
||||
}
|
||||
public static GameEvent newStartGameEvent() {
|
||||
return new GameEvent(Type.START_GAME, null, '_');
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
public enum Type {
|
||||
HINT(Hint.class),
|
||||
GUESS(Card.class),
|
||||
END_GUESSING(Boolean.class),
|
||||
START_GAME(Object.class);
|
||||
|
||||
Class<?> dataType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.bernard.nodecames.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
public class Grid {
|
||||
|
||||
String id;
|
||||
|
||||
Card[] cards;
|
||||
|
||||
List<GameEvent> gameEvents;
|
||||
Hint currentHint = null;
|
||||
int currentGuessCount;
|
||||
|
||||
int usedHints;
|
||||
int usedWhites;
|
||||
|
||||
Phase phase;
|
||||
|
||||
public Grid(String name, Card[] cards) {
|
||||
this(name, cards, new ArrayList<>(), null, 0, 0, 0, Phase.HINTING_ANY);
|
||||
}
|
||||
|
||||
public void incrementHintCount() {
|
||||
this.setUsedHints(this.getUsedHints()+1);
|
||||
}
|
||||
public void incrementWhiteCount() {
|
||||
this.setUsedWhites(this.getUsedWhites()+1);
|
||||
}
|
||||
public void incrementCurrentGuessCount() {
|
||||
this.setCurrentGuessCount(this.getCurrentGuessCount()+1);
|
||||
}
|
||||
public void newGameEvent(GameEvent event) {
|
||||
this.gameEvents.add(event);
|
||||
}
|
||||
public int getCardCount() {
|
||||
return this.getCards().length;
|
||||
}
|
||||
|
||||
public enum Phase {
|
||||
HINTING_ANY,
|
||||
HINTING_A,
|
||||
HINTING_B,
|
||||
GUESSING_A,
|
||||
GUESSING_B;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.bernard.nodecames.model;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class Hint {
|
||||
|
||||
String word;
|
||||
int wordCount;
|
||||
|
||||
public boolean canStillGuess(int guessCount) {
|
||||
return (wordCount == -1) || (guessCount < (wordCount + 1));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,7 +21,7 @@ spring:
|
||||
|
||||
jpa:
|
||||
properties:
|
||||
javax:
|
||||
jakarta:
|
||||
persistence:
|
||||
schema-generation:
|
||||
create-source: metadata
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
li.card {
|
||||
border: purple solid 2pt;
|
||||
list-style-type: none;
|
||||
padding: 1ex;
|
||||
margin: 1ex;
|
||||
font-size: 16px;
|
||||
}
|
||||
ul#cards-list {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
|
||||
span.card-word {
|
||||
font-weight: bold;
|
||||
font-size: 30px;
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
var socket = null
|
||||
var player = '_'
|
||||
var roomId = '_'
|
||||
var wsHeaders = {}
|
||||
|
||||
function getRoomId() {
|
||||
const urlRegex = /\/room\/([a-f0-9-]{36})\/grid$/
|
||||
const res = urlRegex.exec(window.location.href)
|
||||
if (res == null)
|
||||
console.log("Could not understand room id from url")
|
||||
return res[1]
|
||||
}
|
||||
|
||||
function makeCards(data) {
|
||||
var cards = data['cards']
|
||||
$('#cards-list').empty()
|
||||
for(var i = 0; i<cards.length; i++) {
|
||||
html = `
|
||||
<li class="card" id="card-${i}">
|
||||
<span class="card-word">${cards[i].word}</span><br/>
|
||||
Color: <span class="card-color-text" id="card-${i}-color">${cards[i].color}</span><br/>
|
||||
<button id="card-${i}-button">Toucher</button>
|
||||
</li>
|
||||
`
|
||||
$('#cards-list').append($(html))
|
||||
$(`#card-${i}-button`).on('click', pointCard)
|
||||
}
|
||||
}
|
||||
|
||||
function selectPlayer(e) {
|
||||
console.log(e)
|
||||
console.log(e.target)
|
||||
console.log(e.target.id)
|
||||
console.log(e.target.id == "select-player-a")
|
||||
player = (e.target.id == "select-player-a") ? 'A' : 'B'
|
||||
wsHeaders = {
|
||||
"room": roomId,
|
||||
"player": player
|
||||
}
|
||||
|
||||
$('#player-selector').hide()
|
||||
$('#game-panel').show()
|
||||
$.ajax({
|
||||
contentType: 'application/json',
|
||||
type: "GET",
|
||||
url: "/room/"+roomId+"/game/player-"+player.toLowerCase(),
|
||||
success: makeCards
|
||||
})
|
||||
|
||||
socket = Stomp.over(new SockJS('/socket'));
|
||||
socket.connect({}, function (frame) {
|
||||
socket.subscribe('/topic/submit-hint', onSubmitHint);
|
||||
socket.subscribe('/topic/point-card', onPointCard);
|
||||
socket.subscribe('/topic/end-guessing', onEndGuessing);
|
||||
});
|
||||
}
|
||||
|
||||
function submitHint(e) {
|
||||
hint = $('#submit-hint-text').val()
|
||||
hintWordCount = Number($('#submit-hint-wordcount option:selected').val())
|
||||
socket.send('/app/submit-hint', wsHeaders, JSON.stringify({
|
||||
'hint': hint,
|
||||
'hintWordCount': hintWordCount
|
||||
}))
|
||||
}
|
||||
function pointCard(e) {
|
||||
cardIndex = Number(/card-([0-9]+)-button/.exec(e.target.id)[1])
|
||||
socket.send('/app/point-card', wsHeaders, JSON.stringify({
|
||||
'cardIndex': cardIndex,
|
||||
}))
|
||||
}
|
||||
function endGuessing(e) {
|
||||
socket.send('/app/end-guessing', wsHeaders, "")
|
||||
}
|
||||
|
||||
function onSubmitHint(m) {
|
||||
data = JSON.parse(m.body)
|
||||
$("#event-log").append($(`
|
||||
<li>
|
||||
${data['hint']} en ${data['hintWordCount']}
|
||||
</li>
|
||||
`))
|
||||
}
|
||||
function onPointCard(m) {
|
||||
data = JSON.parse(m.body)
|
||||
$("#event-log").append($(`
|
||||
<li>
|
||||
Pointed card ${data['cardIndex']}
|
||||
</li>
|
||||
`))
|
||||
}
|
||||
function onEndGuessing(m) {
|
||||
$("#event-log").append($(`
|
||||
<li>
|
||||
Ended guessing
|
||||
</li>
|
||||
`))
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
$('#select-player-a').on('click', selectPlayer)
|
||||
$('#select-player-b').on('click', selectPlayer)
|
||||
$('#submit-hint button').on('click', submitHint)
|
||||
$('#end-guessing-button').on('click', endGuessing)
|
||||
|
||||
roomId = getRoomId()
|
||||
|
||||
$('#game-panel').hide()
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,49 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr" dir="ltr">
|
||||
<head>
|
||||
<div th:replace="~{html-head}"/>
|
||||
<link rel="stylesheet" th:href="@{/css/grid.css}"/>
|
||||
<script th:src="@{/js/jquery-4.0.0.min.js}" type="text/javascript"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.6.1/sockjs.min.js" integrity="sha512-1QvjE7BtotQjkq8PxLeF6P46gEpBRXuskzIVgjFpekzFVF4yjRgrQvTG1MTOJ3yQgvTteKAcO7DSZI92+u/yZw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js" integrity="sha512-iKDtgDyTHjAitUDdLljGhenhPwrbBfqTKWO1mkhSFH3A7blITC9MhYon6SjnMhp4o0rADGw9yAC6EW4t5a4K3g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script th:src="@{/js/grid.js}" type="text/javascript"></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div id="player-selector">
|
||||
Which player are you ? <br/>
|
||||
<button id="select-player-a">Player A</button>
|
||||
<button id="select-player-b">Player B</button>
|
||||
</div>
|
||||
|
||||
<div id="game-panel">
|
||||
<ul id="cards-list">
|
||||
|
||||
</ul>
|
||||
|
||||
<div id="submit-hint">
|
||||
<input type="text" id="submit-hint-text"/>
|
||||
<select id="submit-hint-wordcount">
|
||||
<option value="0">0</option>
|
||||
<option value="1">1</option>
|
||||
<option value="2">2</option>
|
||||
<option value="3">3</option>
|
||||
<option value="4">4</option>
|
||||
<option value="5">5</option>
|
||||
</select>
|
||||
<button>Submit Hint</button>
|
||||
</div>
|
||||
<button id="end-guessing-button">End Guessing</button>
|
||||
<br/>
|
||||
<ol id="event-log">
|
||||
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
</main>
|
||||
<script>
|
||||
initialize()
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user