Files
NodeCames/src/main/java/com/bernard/nodecames/model/Grid.java
T

186 lines
6.3 KiB
Java
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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();
}
}
}