Added a config page
This commit is contained in:
@@ -1,15 +1,25 @@
|
||||
package com.bernard.nodecames;
|
||||
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.servlet.view.RedirectView;
|
||||
|
||||
import com.bernard.nodecames.frontend.GridConfigEdit;
|
||||
import com.bernard.nodecames.game.GameManager;
|
||||
import com.bernard.nodecames.game.IllegalGameActionException;
|
||||
import com.bernard.nodecames.model.Grid;
|
||||
import com.bernard.nodecames.model.GridConfig;
|
||||
import com.bernard.nodecames.model.GridConfig.MutableOption;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@@ -30,6 +40,30 @@ public class HttpController {
|
||||
return "grid";
|
||||
}
|
||||
|
||||
@GetMapping("/room/{id}/config")
|
||||
public String gridConfig(@PathVariable("id") String id, Model model) {
|
||||
GridConfig gc = gm.findGrid(id).getConfig();
|
||||
model.addAttribute("gridConfig", GridConfigEdit.of(gc));
|
||||
return "grid-config";
|
||||
}
|
||||
@PostMapping("/room/{id}/config")
|
||||
public String setGridConfig(@PathVariable("id") String id,
|
||||
@ModelAttribute("gridConfig") GridConfigEdit gce,
|
||||
BindingResult br,
|
||||
Model model
|
||||
) {
|
||||
Grid g = gm.findGrid(id);
|
||||
for(Entry<MutableOption, Object> e : gce.getModifications(g.getConfig()).entrySet()) {
|
||||
try {
|
||||
gm.unlock(g, e.getKey(), e.getValue());
|
||||
} catch (IllegalGameActionException ige) {
|
||||
br.addError(new ObjectError(e.getKey().name(), ige.getMessage()));
|
||||
}
|
||||
}
|
||||
model.addAttribute("contactForm", gce);
|
||||
return "grid-config";
|
||||
}
|
||||
|
||||
|
||||
|
||||
@GetMapping("/create-room")
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
package com.bernard.nodecames.frontend;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.bernard.nodecames.model.GridConfig;
|
||||
import com.bernard.nodecames.model.GridConfig.MutableOption;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class GridConfigEdit {
|
||||
|
||||
private int maxHint;
|
||||
private String availableHintWordCountStr; // Comma separated integers
|
||||
private boolean oneMoreGuess;
|
||||
private int hintMaxLength;
|
||||
private boolean endGuessing;
|
||||
private boolean onlyOneGreenGreen;
|
||||
private boolean suddenDeath;
|
||||
private boolean hintsInARow;
|
||||
|
||||
public static GridConfigEdit of(GridConfig gc) {
|
||||
return new GridConfigEdit(
|
||||
gc.getMaxHint(),
|
||||
gc.getAvailableHintWordCount()
|
||||
.stream()
|
||||
.sorted()
|
||||
.map(Object::toString)
|
||||
.collect(Collectors.joining(",")),
|
||||
gc.isOneMoreGuess(),
|
||||
gc.getHintMaxLength(),
|
||||
gc.isEndGuessing(),
|
||||
gc.isOnlyOneGreenGreen(),
|
||||
gc.isSuddenDeath(),
|
||||
gc.isHintsInARow()
|
||||
);
|
||||
}
|
||||
|
||||
public Set<Integer> getAvailableHintWordCount() {
|
||||
return Stream.of(this.getAvailableHintWordCountStr().split(","))
|
||||
.map(Integer::parseInt)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public Map<MutableOption, Object> getMutableOptions() {
|
||||
return Map.of(
|
||||
MutableOption.MAX_HINT, this.getMaxHint(),
|
||||
MutableOption.AVAILABLE_HINT_WORD_COUNT, this.getAvailableHintWordCount(),
|
||||
MutableOption.ONE_MORE_GUESS, this.isOneMoreGuess(),
|
||||
MutableOption.HINT_MAX_LENGTH, this.getHintMaxLength(),
|
||||
MutableOption.END_GUESSING, this.isEndGuessing(),
|
||||
MutableOption.ONLY_ONE_GREEN_GREEN, this.isOnlyOneGreenGreen(),
|
||||
MutableOption.SUDDEN_DEATH, this.isSuddenDeath(),
|
||||
MutableOption.HINTS_IN_A_ROW, this.isHintsInARow()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of modified in this edit compared to the GridConfig
|
||||
*/
|
||||
public Map<MutableOption, Object> getModifications(GridConfig orig) {
|
||||
Map<MutableOption, Object> out = new EnumMap<>(MutableOption.class);
|
||||
Map<MutableOption, Object> selfOpts = this.getMutableOptions();
|
||||
for(Entry<MutableOption, Object> e : orig.getMutableOptions().entrySet()) {
|
||||
Object newValue = selfOpts.get(e.getKey());
|
||||
if(!newValue.equals(e.getValue())) {
|
||||
out.put(e.getKey(), newValue);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -305,10 +305,43 @@ public class GameManager {
|
||||
/**
|
||||
* UPDATE GAME CONFIG
|
||||
*/
|
||||
public void unlock(Grid g, MutableOption opt, Object o) throws IllegalGameActionException {
|
||||
switch(opt) {
|
||||
case MutableOption.MAX_HINT:
|
||||
unlockHintCount(g, (Integer)o);
|
||||
break;
|
||||
case MutableOption.AVAILABLE_HINT_WORD_COUNT:
|
||||
unlockNewWordCounts(g, (Set<Integer>)o);
|
||||
break;
|
||||
case MutableOption.ONE_MORE_GUESS:
|
||||
unlockOneMoreGuess(g);
|
||||
break;
|
||||
case MutableOption.HINT_MAX_LENGTH:
|
||||
unlockHintMaxLength(g, (Integer)o);
|
||||
break;
|
||||
case MutableOption.END_GUESSING:
|
||||
unlockEndGuessing(g);
|
||||
break;
|
||||
case MutableOption.ONLY_ONE_GREEN_GREEN:
|
||||
unlockOnlyOneGreenGreen(g);
|
||||
break;
|
||||
case MutableOption.SUDDEN_DEATH:
|
||||
unlockSuddenDeath(g);
|
||||
break;
|
||||
case MutableOption.HINTS_IN_A_ROW:
|
||||
unlockHintsInARow(g);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Unknown MutableOption to edit");
|
||||
}
|
||||
}
|
||||
public void unlockHintCount(Grid g, int newHintCount) throws IllegalGameActionException {
|
||||
if(newHintCount > g.getConfig().getMaxMaxHint() || newHintCount <= g.getConfig().getMaxHint()) {
|
||||
if(newHintCount > g.getConfig().getMaxMaxHint()) {
|
||||
throw new IllegalGameActionException(g, "Illegal hint count");
|
||||
}
|
||||
if(newHintCount <= g.getConfig().getMaxHint()) {
|
||||
throw new IllegalGameActionException(g, "Cannot lower hint count");
|
||||
}
|
||||
changeConfig(g, MutableOption.MAX_HINT, newHintCount);
|
||||
if(g.getPhase().isNeedMoreHints() || g.getPhase().isNeedMoreHintsOrSuddenDeath()) {
|
||||
setPhase(g, Phase.hinting(g.getPhase().getHinting()));
|
||||
@@ -326,7 +359,7 @@ public class GameManager {
|
||||
|
||||
public void unlockOneMoreGuess(Grid g) throws IllegalGameActionException {
|
||||
if(g.getConfig().isOneMoreGuess())
|
||||
throw new IllegalGameActionException(g, "Cannot set value, already set");
|
||||
throw new IllegalGameActionException(g, "Cannot unlock oneMoreGuess as it is already unlocked");
|
||||
changeConfig(g, MutableOption.ONE_MORE_GUESS, true);
|
||||
if(g.getPhase().isWaitingForOneMore()) {
|
||||
setPhase(g, Phase.guessing(g.getPhase().getGuessing()));
|
||||
@@ -342,13 +375,13 @@ public class GameManager {
|
||||
|
||||
public void unlockEndGuessing(Grid g) throws IllegalGameActionException {
|
||||
if(g.getConfig().isEndGuessing())
|
||||
throw new IllegalGameActionException(g, "Cannot set value, already set");
|
||||
throw new IllegalGameActionException(g, "Cannot unlock endGuessing as it is already unlocked");
|
||||
changeConfig(g, MutableOption.END_GUESSING, true);
|
||||
}
|
||||
|
||||
public void unlockOnlyOneGreenGreen(Grid g) throws IllegalGameActionException {
|
||||
if(g.getConfig().isOnlyOneGreenGreen())
|
||||
throw new IllegalGameActionException(g, "Cannot set value, already set");
|
||||
throw new IllegalGameActionException(g, "Cannot unlock onlyOneGreenGreen as it is already unlocked");
|
||||
changeConfig(g, MutableOption.ONLY_ONE_GREEN_GREEN, true);
|
||||
if(g.getPhase() == Phase.WIN_IF_GREEN_GREEN) {
|
||||
endGame(g, true);
|
||||
@@ -357,7 +390,7 @@ public class GameManager {
|
||||
|
||||
public void unlockSuddenDeath(Grid g) throws IllegalGameActionException {
|
||||
if(g.getConfig().isSuddenDeath())
|
||||
throw new IllegalGameActionException(g, "Cannot set value, already set");
|
||||
throw new IllegalGameActionException(g, "Cannot unlock suddenDeath as it is already unlocked");
|
||||
changeConfig(g, MutableOption.SUDDEN_DEATH,true);
|
||||
if (g.getPhase().isNeedMoreHintsOrSuddenDeath()) {
|
||||
setPhase(g, Phase.needMoreHints(g.getPhase().getHinting()));
|
||||
@@ -369,7 +402,7 @@ public class GameManager {
|
||||
|
||||
public void unlockHintsInARow(Grid g) throws IllegalGameActionException {
|
||||
if(g.getConfig().isHintsInARow())
|
||||
throw new IllegalGameActionException(g, "Cannot set value, already set");
|
||||
throw new IllegalGameActionException(g, "Cannot unlock hintsInARow as it is already unlocked");
|
||||
changeConfig(g, MutableOption.HINTS_IN_A_ROW,true);
|
||||
if ((g.getPhase() == Phase.HINTING_A || g.getPhase() == Phase.HINTING_B)
|
||||
&& !allGreenRevealed(g, 'A', g.getConfig().isOnlyOneGreenGreen())
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
package com.bernard.nodecames.model;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.bernard.nodecames.model.Card.Color;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.Value;
|
||||
import lombok.With;
|
||||
|
||||
import static com.bernard.nodecames.model.GridConfig.CardColors.BB;
|
||||
import static com.bernard.nodecames.model.GridConfig.CardColors.BG;
|
||||
import static com.bernard.nodecames.model.GridConfig.CardColors.BW;
|
||||
@@ -22,6 +10,17 @@ import static com.bernard.nodecames.model.GridConfig.CardColors.WB;
|
||||
import static com.bernard.nodecames.model.GridConfig.CardColors.WG;
|
||||
import static com.bernard.nodecames.model.GridConfig.CardColors.WW;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.bernard.nodecames.model.Card.Color;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.Value;
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class GridConfig {
|
||||
@@ -107,6 +106,23 @@ public class GridConfig {
|
||||
}
|
||||
}
|
||||
|
||||
public Map<MutableOption, Object> getMutableOptions() {
|
||||
return Map.of(
|
||||
MutableOption.MAX_HINT, this.getMaxHint(),
|
||||
MutableOption.AVAILABLE_HINT_WORD_COUNT, this.getAvailableHintWordCount(),
|
||||
MutableOption.ONE_MORE_GUESS, this.isOneMoreGuess(),
|
||||
MutableOption.HINT_MAX_LENGTH, this.getHintMaxLength(),
|
||||
MutableOption.END_GUESSING, this.isEndGuessing(),
|
||||
MutableOption.ONLY_ONE_GREEN_GREEN, this.isOnlyOneGreenGreen(),
|
||||
MutableOption.SUDDEN_DEATH, this.isSuddenDeath(),
|
||||
MutableOption.HINTS_IN_A_ROW, this.isHintsInARow()
|
||||
);
|
||||
}
|
||||
|
||||
public static final boolean isGenericallyValidHintWordCount(int i) {
|
||||
return 0 <= i || i == -1;
|
||||
}
|
||||
|
||||
@Value(staticConstructor = "of")
|
||||
public static final class CardColors {
|
||||
Color faceA;
|
||||
|
||||
@@ -300,7 +300,7 @@ function onUpdateCard(m) {
|
||||
|
||||
function onConfigChange(m) {
|
||||
data = JSON.parse(m.body)
|
||||
for(const [key, value] of data.entries()) {
|
||||
for(const [key, value] of Object.entries(data)) {
|
||||
console.log("New config option : ", key, "=", value)
|
||||
gc[key] = value
|
||||
switch(key) {
|
||||
@@ -320,8 +320,6 @@ function onConfigChange(m) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
cards[i] = data
|
||||
updateCard(i)
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<!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>
|
||||
<form method="POST"
|
||||
action="" th:object="${gridConfig}">
|
||||
<ul th:if="${#fields.hasErrors('global')}">
|
||||
<li th:each="error : ${#fields.errors('global')}" th:text="${error}">error</li>
|
||||
</ul>
|
||||
<label th:field="maxHint" for="field-max-hint">Maximum number of hints</label>
|
||||
<input th:field="*{maxHint}" id="field-max-hint"/> <br/>
|
||||
<label th:field="availableHintWordCountStr" for="field-available-hint-word-count">Available hint's word counts<label>
|
||||
<input th:field="*{availableHintWordCountStr}" id="field-available-hint-word-count"/> <br/>
|
||||
<label th:field="oneMoreGuess" for="field-one-more-guess">Can do one more guess than hint word count</label>
|
||||
<input type="checkbox" th:field="*{oneMoreGuess}" id="field-one-more-guess"/> <br/>
|
||||
<label th:field="hintMaxLength" for="field-hint-max-length">Maximum length of hint words</label>
|
||||
<input th:field="*{hintMaxLength}" id="field-hint-max-length"/> <br/>
|
||||
<label th:field="endGuessing" for="field-end-guessing">Can press end guessing before the number of words</label>
|
||||
<input type="checkbox" th:field="*{endGuessing}" id="field-end-guessing"/> <br/>
|
||||
<label th:field="onlyOneGreenGreen" for="field-only-one-green-green">Green-Green cards only have to be pressed by one side</label>
|
||||
<input type="checkbox" th:field="*{onlyOneGreenGreen}" id="field-only-one-green-green"/> <br/>
|
||||
<label th:field="suddenDeath" for="field-sudden-death">Before losing beccause no more hints, goes to sudden death</label>
|
||||
<input type="checkbox" th:field="*{suddenDeath}" id="field-sudden-death"/> <br/>
|
||||
<label th:field="hintsInARow" for="field-hints-in-a-row">Someone can propose two hints in a row</label>
|
||||
<input type="checkbox" th:field="*{hintsInARow}" id="field-hints-in-a-row"/> <br/>
|
||||
<input type="submit" value="Change config" />
|
||||
</form>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user