186 lines
6.3 KiB
Java
186 lines
6.3 KiB
Java
package com.bernard.nodecames.model;
|
||
|
||
import java.util.ArrayList;
|
||
import java.util.List;
|
||
import java.util.Optional;
|
||
import java.util.Set;
|
||
import java.util.UUID;
|
||
|
||
import org.hibernate.annotations.JdbcTypeCode;
|
||
import org.hibernate.type.SqlTypes;
|
||
|
||
import jakarta.annotation.Nullable;
|
||
import jakarta.persistence.AttributeConverter;
|
||
import jakarta.persistence.CascadeType;
|
||
import jakarta.persistence.Column;
|
||
import jakarta.persistence.Convert;
|
||
import jakarta.persistence.Embedded;
|
||
import jakarta.persistence.Entity;
|
||
import jakarta.persistence.FetchType;
|
||
import jakarta.persistence.Id;
|
||
import jakarta.persistence.ManyToOne;
|
||
import jakarta.persistence.OneToMany;
|
||
import lombok.AllArgsConstructor;
|
||
import lombok.Getter;
|
||
import lombok.NoArgsConstructor;
|
||
import lombok.Setter;
|
||
import tools.jackson.databind.JsonNode;
|
||
import tools.jackson.databind.node.ArrayNode;
|
||
import tools.jackson.databind.node.JsonNodeFactory;
|
||
|
||
@NoArgsConstructor
|
||
@AllArgsConstructor
|
||
@Getter
|
||
@Setter
|
||
@Entity
|
||
public class Grid {
|
||
|
||
@Id
|
||
UUID id;
|
||
|
||
@ManyToOne(optional = true)
|
||
World w;
|
||
|
||
//@Type(JsonType.class)
|
||
@Column(columnDefinition = "json")
|
||
@Convert(converter = GameEventListAdapter.class)
|
||
@JdbcTypeCode(SqlTypes.JSON)
|
||
List<GameEvent> gameEvents;
|
||
|
||
@Embedded
|
||
Hint currentHint = null;
|
||
int currentGuessCount;
|
||
|
||
int usedHints;
|
||
int usedWhites;
|
||
|
||
Phase phase;
|
||
|
||
//TODO make this parameter a real Optional<Boolean> with Jdbc understanding that optional means nullable
|
||
@Nullable
|
||
Boolean won;
|
||
|
||
@Embedded
|
||
GridConfig config;
|
||
|
||
public Grid(UUID id, World w, Phase phase, GridConfig config) {
|
||
this(id, w, List.of(), null, 0, 0, 0, phase, null, config);
|
||
}
|
||
|
||
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 = new ArrayList<>(gameEvents);
|
||
this.gameEvents.add(event);
|
||
}
|
||
public Optional<Boolean> isWonOpt() {
|
||
return Optional.ofNullable(this.won);
|
||
}
|
||
public void setWonOpt(Optional<Boolean> won) {
|
||
this.won = won.orElse(null);
|
||
}
|
||
|
||
@AllArgsConstructor
|
||
@Getter
|
||
public enum Phase {
|
||
|
||
HINTING_A('A', ' ', false, false, false),
|
||
HINTING_B('B', ' ', false, false, false),
|
||
GUESSING_A(' ', 'A', false, false, false),
|
||
GUESSING_B(' ', 'B', false, false, false),
|
||
HINTING_BOTH('_', ' ', false, false, false),
|
||
SUDDEN_DEATH_BOTH(' ', '_', true, false, false),
|
||
SUDDEN_DEATH_A(' ', 'A', true, false, false),
|
||
SUDDEN_DEATH_B(' ', 'B', true, false, false),
|
||
GAME_ENDED(' ', ' ', false, true, false),
|
||
// We could go to sudden death OR wait for more hints
|
||
NEED_MORE_HINTS_A('A', ' ', false, false, false),
|
||
NEED_MORE_HINTS_B('B', ' ', false, false, false),
|
||
// We can wait for SUDDEN_DEATH to be unlocked, or wait for more hints
|
||
NEED_MORE_HINTS_OR_SUDDEN_DEATH_A('A', ' ', false, false, true),
|
||
NEED_MORE_HINTS_OR_SUDDEN_DEATH_B('B', ' ', false, false, true),
|
||
// We can only wait for suddenDeath to be unlocked
|
||
NEED_SUDDEN_DEATH(' ', ' ', true, false, true),
|
||
// We can either end guessing, or wait for possibility to do one more guess
|
||
WAITING_FOR_ONE_MORE_A(' ', 'A', false, false, false),
|
||
WAITING_FOR_ONE_MORE_B(' ', 'B', false, false, false),
|
||
// We should have lost the game, we win it if we unlock onlyOneGreenGreen
|
||
WIN_IF_GREEN_GREEN(' ', ' ', false, false, true);
|
||
|
||
// ' ' is none, 'A' is A, 'B' is B, '_' is both
|
||
private char hinting;
|
||
private char guessing;
|
||
private boolean suddenDeath;
|
||
private boolean gameEnded;
|
||
private boolean locked;
|
||
|
||
public boolean isHinting(char player) {
|
||
return (this == HINTING_BOTH) || (this == ((player == 'A')?HINTING_A:HINTING_B));
|
||
}
|
||
public boolean isGuessing(char player) {
|
||
return this == guessing(player) || this == suddenDeathOnly(player) || this == SUDDEN_DEATH_BOTH;
|
||
}
|
||
public boolean isAnyoneGuessing() {
|
||
return isGuessing('A') || isGuessing('B');
|
||
}
|
||
public static Phase hinting(char player) {
|
||
return (player == '_')?HINTING_BOTH:((player == 'A')?HINTING_A:HINTING_B);
|
||
}
|
||
public static Phase guessing(char player) {
|
||
return (player == 'A')?GUESSING_A:GUESSING_B;
|
||
}
|
||
public static Phase suddenDeathOnly(char player) {
|
||
return (player == 'A')?SUDDEN_DEATH_A:SUDDEN_DEATH_B;
|
||
}
|
||
public static Phase needMoreHints(char player) {
|
||
return (player == 'A')?NEED_MORE_HINTS_A:NEED_MORE_HINTS_B;
|
||
}
|
||
public static Phase needMoreHintsOrSuddenDeath(char player) {
|
||
return (player == 'A')?NEED_MORE_HINTS_OR_SUDDEN_DEATH_A:NEED_MORE_HINTS_OR_SUDDEN_DEATH_B;
|
||
}
|
||
public static Phase waitingForOneMore(char player) {
|
||
return (player == 'A')?WAITING_FOR_ONE_MORE_A:WAITING_FOR_ONE_MORE_B;
|
||
}
|
||
public boolean isWaitingForOneMore() {
|
||
return this == WAITING_FOR_ONE_MORE_A || this == WAITING_FOR_ONE_MORE_B;
|
||
}
|
||
public boolean canPlay() {
|
||
return !this.isGameEnded() && !this.isLocked();
|
||
}
|
||
public boolean isNeedMoreHints() {
|
||
return this == NEED_MORE_HINTS_A || this == NEED_MORE_HINTS_B;
|
||
}
|
||
public boolean isNeedMoreHintsOrSuddenDeath() {
|
||
return this == NEED_MORE_HINTS_OR_SUDDEN_DEATH_A || this == NEED_MORE_HINTS_OR_SUDDEN_DEATH_B;
|
||
}
|
||
}
|
||
|
||
@AllArgsConstructor
|
||
public static class GameEventListAdapter implements AttributeConverter<List<GameEvent>, JsonNode> {
|
||
|
||
JsonNodeFactory jsn;
|
||
|
||
@Override
|
||
public JsonNode convertToDatabaseColumn(List<GameEvent> attribute) {
|
||
ArrayNode out = jsn.arrayNode(attribute.size());
|
||
for(GameEvent ge : attribute) {
|
||
out.add(GameEvent.toJsonNode(ge));
|
||
}
|
||
return out;
|
||
}
|
||
|
||
@Override
|
||
public List<GameEvent> convertToEntityAttribute(JsonNode dbData) {
|
||
return dbData.asArray().valueStream().map(GameEvent::fromJsonNode).toList();
|
||
}
|
||
|
||
}
|
||
}
|