cleanup: remove moved code
This commit is contained in:
		@ -1,177 +0,0 @@
 | 
				
			|||||||
package uulm.teamname.marvelous.gamelibrary.ai;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.config.CharacterConfig;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.config.PartyConfig;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.config.ScenarioConfig;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.entities.Character;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.entities.EntityID;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.entities.EntityType;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.gamelogic.GameStateView;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.requests.Request;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.requests.RequestBuilder;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.requests.RequestType;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** Represents an AI instance for calculations. */
 | 
					 | 
				
			||||||
class AI {
 | 
					 | 
				
			||||||
    /** The {@link GameStateView} the AI is playing on. */
 | 
					 | 
				
			||||||
    private final GameStateView state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** The Player the AI is playing for. */
 | 
					 | 
				
			||||||
    private final EntityType player;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** The config data. */
 | 
					 | 
				
			||||||
    private final PartyConfig partyConfig;
 | 
					 | 
				
			||||||
    private final CharacterConfig characterConfig;
 | 
					 | 
				
			||||||
    private final ScenarioConfig scenarioConfig;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** Constructs a new {@link AI} playing the given player based on the given config values. */
 | 
					 | 
				
			||||||
    public AI(GameStateView state, EntityType player, PartyConfig partyConfig, CharacterConfig characterConfig, ScenarioConfig scenarioConfig) {
 | 
					 | 
				
			||||||
        this.state = state;
 | 
					 | 
				
			||||||
        this.player = player;
 | 
					 | 
				
			||||||
        this.partyConfig = partyConfig;
 | 
					 | 
				
			||||||
        this.characterConfig = characterConfig;
 | 
					 | 
				
			||||||
        this.scenarioConfig = scenarioConfig;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Calculates the appropriate actions for a turn of any of the characters the AI is playing for.
 | 
					 | 
				
			||||||
     * @param turn The {@link EntityID} that currently has the turn
 | 
					 | 
				
			||||||
     * @return A list of {@link Request Requests} with the actions the AI wants to perform
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public ArrayList<Request> performTurn(EntityID turn) {
 | 
					 | 
				
			||||||
        System.out.println("[AI] Handling Character " + turn + " for Player " + player + ":");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        ArrayList<Request> result = new ArrayList<>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Character character = (Character)state.getEntities().findEntity(turn);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        BoardAnalyzer analyzer = new BoardAnalyzer(state, turn);
 | 
					 | 
				
			||||||
        Action action = analyzer.analyze(state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        switch(action.type) {
 | 
					 | 
				
			||||||
            case None -> {
 | 
					 | 
				
			||||||
                System.out.println("     Result: doing nothing");
 | 
					 | 
				
			||||||
                result.add(new RequestBuilder(RequestType.EndRoundRequest)
 | 
					 | 
				
			||||||
                        .buildGameRequest());
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case Move -> {
 | 
					 | 
				
			||||||
                System.out.println("     Result: moving to " + action.target);
 | 
					 | 
				
			||||||
                result.add(new RequestBuilder(RequestType.MoveRequest)
 | 
					 | 
				
			||||||
                        .withOriginEntity(turn)
 | 
					 | 
				
			||||||
                        .withOriginField(character.getPosition())
 | 
					 | 
				
			||||||
                        .withTargetField(action.target)
 | 
					 | 
				
			||||||
                        .buildCharacterRequest());
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case MeleeAttack -> {
 | 
					 | 
				
			||||||
                System.out.println("     Result: melee attacking " + action.targetEntity);
 | 
					 | 
				
			||||||
                Character target = (Character)state.getEntities().findEntity(action.targetEntity);
 | 
					 | 
				
			||||||
                if(target != null) {
 | 
					 | 
				
			||||||
                    result.add(new RequestBuilder(RequestType.MeleeAttackRequest)
 | 
					 | 
				
			||||||
                            .withOriginEntity(turn)
 | 
					 | 
				
			||||||
                            .withTargetEntity(action.targetEntity)
 | 
					 | 
				
			||||||
                            .withOriginField(character.getPosition())
 | 
					 | 
				
			||||||
                            .withTargetField(action.target)
 | 
					 | 
				
			||||||
                            .withValue(character.meleeDamage)
 | 
					 | 
				
			||||||
                            .buildCharacterRequest());
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case RangedAttack -> {
 | 
					 | 
				
			||||||
                System.out.println("     Result: ranged attacking " + action.targetEntity);
 | 
					 | 
				
			||||||
                Character target = (Character)state.getEntities().findEntity(action.targetEntity);
 | 
					 | 
				
			||||||
                if(target != null) {
 | 
					 | 
				
			||||||
                    result.add(new RequestBuilder(RequestType.RangedAttackRequest)
 | 
					 | 
				
			||||||
                            .withOriginEntity(turn)
 | 
					 | 
				
			||||||
                            .withTargetEntity(action.targetEntity)
 | 
					 | 
				
			||||||
                            .withOriginField(character.getPosition())
 | 
					 | 
				
			||||||
                            .withTargetField(action.target)
 | 
					 | 
				
			||||||
                            .withValue(character.rangedDamage)
 | 
					 | 
				
			||||||
                            .buildCharacterRequest());
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case UseStone -> {
 | 
					 | 
				
			||||||
                switch(action.stone) {
 | 
					 | 
				
			||||||
                    case SpaceStone -> {
 | 
					 | 
				
			||||||
                        System.out.println("     Result: using space stone to " + action.target);
 | 
					 | 
				
			||||||
                        result.add(new RequestBuilder(RequestType.UseInfinityStoneRequest)
 | 
					 | 
				
			||||||
                                .withOriginEntity(turn)
 | 
					 | 
				
			||||||
                                .withOriginField(character.getPosition())
 | 
					 | 
				
			||||||
                                .withTargetField(action.target)
 | 
					 | 
				
			||||||
                                .withStoneType(action.stone)
 | 
					 | 
				
			||||||
                                .buildCharacterRequest());
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    case MindStone -> {
 | 
					 | 
				
			||||||
                        System.out.println("     Result: using mind stone to " + action.target);
 | 
					 | 
				
			||||||
                        result.add(new RequestBuilder(RequestType.UseInfinityStoneRequest)
 | 
					 | 
				
			||||||
                                .withOriginEntity(turn)
 | 
					 | 
				
			||||||
                                .withOriginField(character.getPosition())
 | 
					 | 
				
			||||||
                                .withTargetField(action.target)
 | 
					 | 
				
			||||||
                                .withValue(partyConfig.mindStoneDMG)
 | 
					 | 
				
			||||||
                                .withStoneType(action.stone)
 | 
					 | 
				
			||||||
                                .buildCharacterRequest());
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    case RealityStone -> {
 | 
					 | 
				
			||||||
                        System.out.println("     Result: using reality stone at " + action.target);
 | 
					 | 
				
			||||||
                        result.add(new RequestBuilder(RequestType.UseInfinityStoneRequest)
 | 
					 | 
				
			||||||
                                .withOriginEntity(turn)
 | 
					 | 
				
			||||||
                                .withTargetEntity(action.targetEntity)
 | 
					 | 
				
			||||||
                                .withOriginField(character.getPosition())
 | 
					 | 
				
			||||||
                                .withTargetField(action.target)
 | 
					 | 
				
			||||||
                                .withStoneType(action.stone)
 | 
					 | 
				
			||||||
                                .buildCharacterRequest());
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    case PowerStone -> {
 | 
					 | 
				
			||||||
                        System.out.println("     Result: using power stone against " + action.targetEntity);
 | 
					 | 
				
			||||||
                        result.add(new RequestBuilder(RequestType.UseInfinityStoneRequest)
 | 
					 | 
				
			||||||
                                .withOriginEntity(turn)
 | 
					 | 
				
			||||||
                                .withTargetEntity(action.targetEntity)
 | 
					 | 
				
			||||||
                                .withOriginField(character.getPosition())
 | 
					 | 
				
			||||||
                                .withTargetField(action.target)
 | 
					 | 
				
			||||||
                                .withValue(character.rangedDamage * 2)
 | 
					 | 
				
			||||||
                                .withStoneType(action.stone)
 | 
					 | 
				
			||||||
                                .buildCharacterRequest());
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    case TimeStone -> {
 | 
					 | 
				
			||||||
                        System.out.println("     Result: using time stone");
 | 
					 | 
				
			||||||
                        result.add(new RequestBuilder(RequestType.UseInfinityStoneRequest)
 | 
					 | 
				
			||||||
                                .withOriginEntity(turn)
 | 
					 | 
				
			||||||
                                .withOriginField(character.getPosition())
 | 
					 | 
				
			||||||
                                .withStoneType(action.stone)
 | 
					 | 
				
			||||||
                                .buildCharacterRequest());
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    case SoulStone -> {
 | 
					 | 
				
			||||||
                        System.out.println("     Result: using soul stone on " + action.targetEntity);
 | 
					 | 
				
			||||||
                        result.add(new RequestBuilder(RequestType.UseInfinityStoneRequest)
 | 
					 | 
				
			||||||
                                .withOriginEntity(turn)
 | 
					 | 
				
			||||||
                                .withTargetEntity(action.targetEntity)
 | 
					 | 
				
			||||||
                                .withOriginField(character.getPosition())
 | 
					 | 
				
			||||||
                                .withTargetField(action.target)
 | 
					 | 
				
			||||||
                                .withStoneType(action.stone)
 | 
					 | 
				
			||||||
                                .buildCharacterRequest());
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case GiveStone -> {
 | 
					 | 
				
			||||||
                System.out.println("     Result: giving stone to " + action.targetEntity);
 | 
					 | 
				
			||||||
                Character target = (Character)state.getEntities().findEntity(action.targetEntity);
 | 
					 | 
				
			||||||
                if(target != null) {
 | 
					 | 
				
			||||||
                    result.add(new RequestBuilder(RequestType.ExchangeInfinityStoneRequest)
 | 
					 | 
				
			||||||
                            .withOriginEntity(turn)
 | 
					 | 
				
			||||||
                            .withTargetEntity(action.targetEntity)
 | 
					 | 
				
			||||||
                            .withOriginField(character.getPosition())
 | 
					 | 
				
			||||||
                            .withTargetField(action.target)
 | 
					 | 
				
			||||||
                            .withStoneType(action.stone)
 | 
					 | 
				
			||||||
                            .buildCharacterRequest());
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case EndTurn -> {
 | 
					 | 
				
			||||||
                System.out.println("     Result: ending turn");
 | 
					 | 
				
			||||||
                result.add(new RequestBuilder(RequestType.EndRoundRequest)
 | 
					 | 
				
			||||||
                        .buildGameRequest());
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return result;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,64 +0,0 @@
 | 
				
			|||||||
package uulm.teamname.marvelous.gamelibrary.ai;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.config.CharacterConfig;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.config.PartyConfig;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.config.ScenarioConfig;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.entities.EntityType;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.events.Event;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.events.EventType;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.gamelogic.GameInstance;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.requests.Request;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
import java.util.Optional;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** Represents an AI player. */
 | 
					 | 
				
			||||||
public class AIClient {
 | 
					 | 
				
			||||||
    /** The {@link GameInstance} the AI is playing on. */
 | 
					 | 
				
			||||||
    private final GameInstance game;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** The Player the AI is playing for. */
 | 
					 | 
				
			||||||
    private final EntityType player;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** The actual {@link AI} instance. */
 | 
					 | 
				
			||||||
    private final AI ai;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /** Constructs a new {@link AIClient} playing the given player based on the given config values. */
 | 
					 | 
				
			||||||
    public AIClient(EntityType player, PartyConfig partyConfig, CharacterConfig characterConfig, ScenarioConfig scenarioConfig) {
 | 
					 | 
				
			||||||
        this.game = new GameInstance(partyConfig, characterConfig, scenarioConfig);
 | 
					 | 
				
			||||||
        this.player = player;
 | 
					 | 
				
			||||||
        this.ai = new AI(game.state, player, partyConfig, characterConfig, scenarioConfig);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Handles incoming {@link Event Events} and optionally returns a list of response {@link Request Requests}.
 | 
					 | 
				
			||||||
     * @param events The incoming events
 | 
					 | 
				
			||||||
     * @return Optionally resulting requests
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public Optional<List<Request>> handle(Event... events) {
 | 
					 | 
				
			||||||
        ArrayList<Request> result = new ArrayList<>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        game.applyEvents(events);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        boolean containsTurn = false;
 | 
					 | 
				
			||||||
        for(Event event: events) {
 | 
					 | 
				
			||||||
            if(event.type == EventType.TurnEvent) {
 | 
					 | 
				
			||||||
                containsTurn = true;
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        //detect turn
 | 
					 | 
				
			||||||
        if(containsTurn && game.state.getActiveCharacter() != null && game.state.getActiveCharacter().type == player) {
 | 
					 | 
				
			||||||
            //let ai calculate requests
 | 
					 | 
				
			||||||
            result.addAll(this.ai.performTurn(game.state.getActiveCharacter()));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(!result.isEmpty()) {
 | 
					 | 
				
			||||||
            return Optional.of(result);
 | 
					 | 
				
			||||||
        }else {
 | 
					 | 
				
			||||||
            return Optional.empty();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,58 +0,0 @@
 | 
				
			|||||||
package uulm.teamname.marvelous.gamelibrary.ai;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.IntVector2;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.entities.EntityID;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.entities.StoneType;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Action {
 | 
					 | 
				
			||||||
    public final ActionType type;
 | 
					 | 
				
			||||||
    public final IntVector2 target;
 | 
					 | 
				
			||||||
    public final EntityID targetEntity;
 | 
					 | 
				
			||||||
    public final StoneType stone;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Action(ActionType type) {
 | 
					 | 
				
			||||||
        this.type = type;
 | 
					 | 
				
			||||||
        this.target = null;
 | 
					 | 
				
			||||||
        this.targetEntity = null;
 | 
					 | 
				
			||||||
        this.stone = null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Action(ActionType type, IntVector2 target) {
 | 
					 | 
				
			||||||
        this.type = type;
 | 
					 | 
				
			||||||
        this.target = target;
 | 
					 | 
				
			||||||
        this.targetEntity = null;
 | 
					 | 
				
			||||||
        this.stone = null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Action(ActionType type, IntVector2 target, EntityID targetEntity) {
 | 
					 | 
				
			||||||
        this.type = type;
 | 
					 | 
				
			||||||
        this.target = target;
 | 
					 | 
				
			||||||
        this.targetEntity = targetEntity;
 | 
					 | 
				
			||||||
        this.stone = null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Action(ActionType type, StoneType stone) {
 | 
					 | 
				
			||||||
        this.type = type;
 | 
					 | 
				
			||||||
        this.target = null;
 | 
					 | 
				
			||||||
        this.targetEntity = null;
 | 
					 | 
				
			||||||
        this.stone = stone;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Action(ActionType type, IntVector2 target, StoneType stone) {
 | 
					 | 
				
			||||||
        this.type = type;
 | 
					 | 
				
			||||||
        this.target = target;
 | 
					 | 
				
			||||||
        this.targetEntity = null;
 | 
					 | 
				
			||||||
        this.stone = stone;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Action(ActionType type, IntVector2 target, EntityID targetEntity, StoneType stone) {
 | 
					 | 
				
			||||||
        this.type = type;
 | 
					 | 
				
			||||||
        this.target = target;
 | 
					 | 
				
			||||||
        this.targetEntity = targetEntity;
 | 
					 | 
				
			||||||
        this.stone = stone;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public String toString() {
 | 
					 | 
				
			||||||
        return this.type.toString();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,11 +0,0 @@
 | 
				
			|||||||
package uulm.teamname.marvelous.gamelibrary.ai;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum ActionType {
 | 
					 | 
				
			||||||
    None,
 | 
					 | 
				
			||||||
    Move,
 | 
					 | 
				
			||||||
    MeleeAttack,
 | 
					 | 
				
			||||||
    RangedAttack,
 | 
					 | 
				
			||||||
    UseStone,
 | 
					 | 
				
			||||||
    GiveStone,
 | 
					 | 
				
			||||||
    EndTurn
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,395 +0,0 @@
 | 
				
			|||||||
package uulm.teamname.marvelous.gamelibrary.ai;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.IntVector2;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.entities.*;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.entities.Character;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.gamelogic.GameLogic;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.gamelogic.GameStateView;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
import java.util.Objects;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Board {
 | 
					 | 
				
			||||||
    private final Piece[][] data;
 | 
					 | 
				
			||||||
    public final EntityType origin;
 | 
					 | 
				
			||||||
    public final EntityID turn;
 | 
					 | 
				
			||||||
    public final boolean ended;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private Board(Piece[][] data, EntityType origin, EntityID turn) {
 | 
					 | 
				
			||||||
        this.data = data;
 | 
					 | 
				
			||||||
        this.origin = origin;
 | 
					 | 
				
			||||||
        this.turn = turn;
 | 
					 | 
				
			||||||
        this.ended = false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private Board(Piece[][] data, EntityType origin, EntityID turn, boolean ended) {
 | 
					 | 
				
			||||||
        this.data = data;
 | 
					 | 
				
			||||||
        this.origin = origin;
 | 
					 | 
				
			||||||
        this.turn = turn;
 | 
					 | 
				
			||||||
        this.ended = ended;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public static Board generate(GameStateView state, EntityID turn) {
 | 
					 | 
				
			||||||
        Piece[][] data = new Piece[state.getMapSize().getY()][state.getMapSize().getX()];
 | 
					 | 
				
			||||||
        for(int x = 0; x < state.getMapSize().getX(); x++) {
 | 
					 | 
				
			||||||
            for(int y = 0; y < state.getMapSize().getY(); y++) {
 | 
					 | 
				
			||||||
                IntVector2 pos = new IntVector2(x, y);
 | 
					 | 
				
			||||||
                ArrayList<Entity> entities = state.getEntities().findByPosition(pos);
 | 
					 | 
				
			||||||
                if(entities.isEmpty()) {
 | 
					 | 
				
			||||||
                    data[y][x] = new Piece(PieceType.Empty);
 | 
					 | 
				
			||||||
                }else {
 | 
					 | 
				
			||||||
                    Entity entity = entities.get(0);
 | 
					 | 
				
			||||||
                    switch(entity.id.type) {
 | 
					 | 
				
			||||||
                        case NPC -> {
 | 
					 | 
				
			||||||
                            if(entity.id.id == NPCType.Thanos.getID()) {
 | 
					 | 
				
			||||||
                                data[y][x] = new Piece(PieceType.Thanos);
 | 
					 | 
				
			||||||
                            }else {
 | 
					 | 
				
			||||||
                                data[y][x] = new Piece(PieceType.NPC);
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        case P1, P2 -> {
 | 
					 | 
				
			||||||
                            Character character = (Character)entity;
 | 
					 | 
				
			||||||
                            data[y][x] = new Piece(
 | 
					 | 
				
			||||||
                                    PieceType.Character,
 | 
					 | 
				
			||||||
                                    entity.id,
 | 
					 | 
				
			||||||
                                    character.hp.getValue(),
 | 
					 | 
				
			||||||
                                    character.hp.getMax(),
 | 
					 | 
				
			||||||
                                    character.mp.getValue(),
 | 
					 | 
				
			||||||
                                    character.mp.getMax(),
 | 
					 | 
				
			||||||
                                    character.ap.getValue(),
 | 
					 | 
				
			||||||
                                    character.ap.getMax(),
 | 
					 | 
				
			||||||
                                    character.inventory.getStonesAsArray()
 | 
					 | 
				
			||||||
                            );
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        case Rocks -> {
 | 
					 | 
				
			||||||
                            Rock rock = (Rock)entity;
 | 
					 | 
				
			||||||
                            data[y][x] = new Piece(PieceType.Rock, entity.id, rock.getHp(), rock.maxHP);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        case Portals -> {
 | 
					 | 
				
			||||||
                            data[y][x] = new Piece(PieceType.Portal, entity.id);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        case InfinityStones -> {
 | 
					 | 
				
			||||||
                            InfinityStone stone = (InfinityStone)entity;
 | 
					 | 
				
			||||||
                            data[y][x] = new Piece(PieceType.InfinityStone, entity.id, stone.type);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        case None -> {
 | 
					 | 
				
			||||||
                            data[y][x] = new Piece(PieceType.Empty);
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return new Board(data, turn.type, turn);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected ArrayList<Action> generateActions(GameStateView state) {
 | 
					 | 
				
			||||||
        ArrayList<Action> result = new ArrayList<>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        EntityType opposite = turn.type == EntityType.P1 ? EntityType.P2 : EntityType.P1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Character character = (Character)state.getEntities().findEntity(turn);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Piece current = null;
 | 
					 | 
				
			||||||
        IntVector2 position = null;
 | 
					 | 
				
			||||||
        for(int x = 0; x < this.data[0].length; x++) {
 | 
					 | 
				
			||||||
            for(int y = 0; y < this.data.length; y++) {
 | 
					 | 
				
			||||||
                if(this.data[y][x].type == PieceType.Character && this.data[y][x].id.equals(turn)) {
 | 
					 | 
				
			||||||
                    current = this.data[y][x];
 | 
					 | 
				
			||||||
                    position = new IntVector2(x, y);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(current == null) {
 | 
					 | 
				
			||||||
            return result;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for(ActionType action: ActionType.values()) {
 | 
					 | 
				
			||||||
            switch(action) {
 | 
					 | 
				
			||||||
                case Move -> {
 | 
					 | 
				
			||||||
                    if(current.mp.getValue() <= 0) {
 | 
					 | 
				
			||||||
                        continue;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    for(IntVector2 dir: IntVector2.CardinalDirections) {
 | 
					 | 
				
			||||||
                        IntVector2 target = position.add(dir);
 | 
					 | 
				
			||||||
                        if(
 | 
					 | 
				
			||||||
                                target.getX() < 0 || target.getX() >= state.getMapSize().getX() ||
 | 
					 | 
				
			||||||
                                target.getY() < 0 || target.getY() >= state.getMapSize().getY()
 | 
					 | 
				
			||||||
                        ) {
 | 
					 | 
				
			||||||
                            continue;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        if(
 | 
					 | 
				
			||||||
                                this.data[target.getY()][target.getX()].type == PieceType.Empty ||
 | 
					 | 
				
			||||||
                                this.data[target.getY()][target.getX()].type == PieceType.Character
 | 
					 | 
				
			||||||
                        ) {
 | 
					 | 
				
			||||||
                            result.add(new Action(ActionType.Move, target));
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                case MeleeAttack -> {
 | 
					 | 
				
			||||||
                    if(current.ap.getValue() <= 0) {
 | 
					 | 
				
			||||||
                        continue;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    for(IntVector2 dir: IntVector2.CardinalDirections) {
 | 
					 | 
				
			||||||
                        IntVector2 target = position.add(dir);
 | 
					 | 
				
			||||||
                        if(target.getX() < 0 || target.getX() >= state.getMapSize().getX() || target.getY() < 0 || target.getY() >= state.getMapSize().getY()) {
 | 
					 | 
				
			||||||
                            continue;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        Piece targetPiece = this.data[target.getY()][target.getX()];
 | 
					 | 
				
			||||||
                        if(targetPiece.type == PieceType.Character && targetPiece.id.type == opposite) {
 | 
					 | 
				
			||||||
                            result.add(new Action(ActionType.MeleeAttack, target, targetPiece.id));
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                case RangedAttack -> {
 | 
					 | 
				
			||||||
                    if(current.ap.getValue() <= 0) {
 | 
					 | 
				
			||||||
                        continue;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    for(int x = 0; x < this.data[0].length; x++) {
 | 
					 | 
				
			||||||
                        for(int y = 0; y < this.data.length; y++) {
 | 
					 | 
				
			||||||
                            IntVector2 pos = new IntVector2(x, y);
 | 
					 | 
				
			||||||
                            float dist = pos.distanceChebyshev(position);
 | 
					 | 
				
			||||||
                            if(this.data[y][x].type == PieceType.Character && this.data[y][x].id.type == opposite && dist > 1 && dist <= character.attackRange && lineOfSight(position, pos)) {
 | 
					 | 
				
			||||||
                                result.add(new Action(ActionType.RangedAttack, pos, this.data[y][x].id));
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                case UseStone -> {
 | 
					 | 
				
			||||||
                    if(current.ap.getValue() <= 0) {
 | 
					 | 
				
			||||||
                        continue;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    for(StoneType stone: StoneType.values()) {
 | 
					 | 
				
			||||||
                        if(state.getStoneCooldown(stone) > 0) {
 | 
					 | 
				
			||||||
                            continue;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        if(!character.inventory.hasStone(stone)) {
 | 
					 | 
				
			||||||
                            continue;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        switch(stone) {
 | 
					 | 
				
			||||||
                            case SpaceStone -> {
 | 
					 | 
				
			||||||
                                for(int x = 0; x < this.data[0].length; x++) {
 | 
					 | 
				
			||||||
                                    for(int y = 0; y < this.data.length; y++) {
 | 
					 | 
				
			||||||
                                        if(this.data[y][x].type == PieceType.Empty) {
 | 
					 | 
				
			||||||
                                            result.add(new Action(ActionType.UseStone, new IntVector2(x, y), stone));
 | 
					 | 
				
			||||||
                                        }
 | 
					 | 
				
			||||||
                                    }
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            case MindStone -> {
 | 
					 | 
				
			||||||
                                for(int x = 0; x < this.data[0].length; x++) {
 | 
					 | 
				
			||||||
                                    for(int y = 0; y < this.data.length; y++) {
 | 
					 | 
				
			||||||
                                        result.add(new Action(ActionType.UseStone, new IntVector2(x, y), stone));
 | 
					 | 
				
			||||||
                                    }
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            case RealityStone -> {
 | 
					 | 
				
			||||||
                                for(IntVector2 dir: IntVector2.CardinalDirections) {
 | 
					 | 
				
			||||||
                                    IntVector2 target = position.add(dir);
 | 
					 | 
				
			||||||
                                    if(target.getX() < 0 || target.getX() >= state.getMapSize().getX() || target.getY() < 0 || target.getY() >= state.getMapSize().getY()) {
 | 
					 | 
				
			||||||
                                        continue;
 | 
					 | 
				
			||||||
                                    }
 | 
					 | 
				
			||||||
                                    Piece targetPiece = this.data[target.getY()][target.getX()];
 | 
					 | 
				
			||||||
                                    if(targetPiece.type == PieceType.Empty) {
 | 
					 | 
				
			||||||
                                        result.add(new Action(ActionType.UseStone, target, turn, stone));
 | 
					 | 
				
			||||||
                                    }else if(targetPiece.type == PieceType.Rock) {
 | 
					 | 
				
			||||||
                                        result.add(new Action(ActionType.UseStone, target, targetPiece.id, stone));
 | 
					 | 
				
			||||||
                                    }
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            case PowerStone -> {
 | 
					 | 
				
			||||||
                                for(IntVector2 dir: IntVector2.CardinalDirections) {
 | 
					 | 
				
			||||||
                                    IntVector2 target = position.add(dir);
 | 
					 | 
				
			||||||
                                    if(target.getX() < 0 || target.getX() >= state.getMapSize().getX() || target.getY() < 0 || target.getY() >= state.getMapSize().getY()) {
 | 
					 | 
				
			||||||
                                        continue;
 | 
					 | 
				
			||||||
                                    }
 | 
					 | 
				
			||||||
                                    Piece targetPiece = this.data[target.getY()][target.getX()];
 | 
					 | 
				
			||||||
                                    if(targetPiece.type == PieceType.Character && targetPiece.id.type == opposite) {
 | 
					 | 
				
			||||||
                                        result.add(new Action(ActionType.UseStone, target, targetPiece.id, stone));
 | 
					 | 
				
			||||||
                                    }
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            case TimeStone -> {
 | 
					 | 
				
			||||||
                                result.add(new Action(ActionType.UseStone, stone));
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            case SoulStone -> {
 | 
					 | 
				
			||||||
                                for(IntVector2 dir: IntVector2.CardinalDirections) {
 | 
					 | 
				
			||||||
                                    IntVector2 target = position.add(dir);
 | 
					 | 
				
			||||||
                                    if(target.getX() < 0 || target.getX() >= state.getMapSize().getX() || target.getY() < 0 || target.getY() >= state.getMapSize().getY()) {
 | 
					 | 
				
			||||||
                                        continue;
 | 
					 | 
				
			||||||
                                    }
 | 
					 | 
				
			||||||
                                    Piece targetPiece = this.data[target.getY()][target.getX()];
 | 
					 | 
				
			||||||
                                    if(targetPiece.type == PieceType.Character && targetPiece.id.type == turn.type && targetPiece.hp.getValue() <= 0) {
 | 
					 | 
				
			||||||
                                        result.add(new Action(ActionType.UseStone, target, targetPiece.id, stone));
 | 
					 | 
				
			||||||
                                    }
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                case GiveStone -> {
 | 
					 | 
				
			||||||
                    if(current.ap.getValue() <= 0) {
 | 
					 | 
				
			||||||
                        continue;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    for(StoneType stone: current.inventory) {
 | 
					 | 
				
			||||||
                        for(IntVector2 dir: IntVector2.CardinalDirections) {
 | 
					 | 
				
			||||||
                            IntVector2 target = position.add(dir);
 | 
					 | 
				
			||||||
                            if(target.getX() < 0 || target.getX() >= state.getMapSize().getX() || target.getY() < 0 || target.getY() >= state.getMapSize().getY()) {
 | 
					 | 
				
			||||||
                                continue;
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                            Piece targetPiece = this.data[target.getY()][target.getX()];
 | 
					 | 
				
			||||||
                            if(targetPiece.type == PieceType.Character && targetPiece.id.type == turn.type) {
 | 
					 | 
				
			||||||
                                result.add(new Action(ActionType.GiveStone, target, targetPiece.id, stone));
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                case EndTurn -> {
 | 
					 | 
				
			||||||
                    result.add(new Action(ActionType.EndTurn));
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return result;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected Board applyAction(GameStateView state, Action action) {
 | 
					 | 
				
			||||||
        Piece[][] clone = new Piece[this.data.length][this.data[0].length];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for(int x = 0; x < this.data[0].length; x++) {
 | 
					 | 
				
			||||||
            for(int y = 0; y < this.data.length; y++) {
 | 
					 | 
				
			||||||
                clone[y][x] = this.data[y][x].clone();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Character character = (Character)state.getEntities().findEntity(turn);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Piece current = null;
 | 
					 | 
				
			||||||
        IntVector2 position = null;
 | 
					 | 
				
			||||||
        for(int x = 0; x < this.data[0].length; x++) {
 | 
					 | 
				
			||||||
            for(int y = 0; y < this.data.length; y++) {
 | 
					 | 
				
			||||||
                if(this.data[y][x].type == PieceType.Character && this.data[y][x].id.equals(turn)) {
 | 
					 | 
				
			||||||
                    current = this.data[y][x];
 | 
					 | 
				
			||||||
                    position = new IntVector2(x, y);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        boolean ended = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        //TODO: finalize action applying
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        switch(action.type) {
 | 
					 | 
				
			||||||
            case Move -> {
 | 
					 | 
				
			||||||
                clone[position.getY()][position.getX()] = clone[action.target.getY()][action.target.getX()];
 | 
					 | 
				
			||||||
                clone[action.target.getY()][action.target.getX()] = current;
 | 
					 | 
				
			||||||
                current.mp.decreaseValue(1);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case MeleeAttack -> {
 | 
					 | 
				
			||||||
                clone[action.target.getY()][action.target.getX()].hp.decreaseValue(character.meleeDamage);
 | 
					 | 
				
			||||||
                current.ap.decreaseValue(1);
 | 
					 | 
				
			||||||
                //todo: drop stones........
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case RangedAttack -> {
 | 
					 | 
				
			||||||
                clone[action.target.getY()][action.target.getX()].hp.decreaseValue(character.rangedDamage);
 | 
					 | 
				
			||||||
                current.ap.decreaseValue(1);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case UseStone -> {
 | 
					 | 
				
			||||||
                switch(action.stone) {
 | 
					 | 
				
			||||||
                    case SpaceStone -> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    case MindStone -> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    case RealityStone -> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    case PowerStone -> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    case TimeStone -> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    case SoulStone -> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case GiveStone -> {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            case EndTurn -> {
 | 
					 | 
				
			||||||
                ended = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(ended || (current.mp.getValue() == 0 && current.ap.getValue() == 0)) {
 | 
					 | 
				
			||||||
            ArrayList<EntityID> alive = new ArrayList<>();
 | 
					 | 
				
			||||||
            for(EntityID next: state.getTurnOrder()) {
 | 
					 | 
				
			||||||
                if(next.type == EntityType.NPC && next.id == NPCType.Thanos.getID()) {
 | 
					 | 
				
			||||||
                    alive.add(next);
 | 
					 | 
				
			||||||
                }else if(next.type == EntityType.P1 || next.type == EntityType.P2) {
 | 
					 | 
				
			||||||
                    if(((Character)state.getEntities().findEntity(next)).isAlive()) {
 | 
					 | 
				
			||||||
                        alive.add(next);
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            int index = alive.indexOf(turn);
 | 
					 | 
				
			||||||
            if(index == alive.size() - 1) {
 | 
					 | 
				
			||||||
                return new Board(clone, origin, turn, true);
 | 
					 | 
				
			||||||
            }else {
 | 
					 | 
				
			||||||
                return new Board(clone, origin, alive.get(index + 1));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }else {
 | 
					 | 
				
			||||||
            return new Board(clone, origin, turn);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected float calculateScore() {
 | 
					 | 
				
			||||||
        float score = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for(int x = 0; x < this.data[0].length; x++) {
 | 
					 | 
				
			||||||
            for(int y = 0; y < this.data.length; y++) {
 | 
					 | 
				
			||||||
                IntVector2 current = new IntVector2(x, y);
 | 
					 | 
				
			||||||
                Piece piece = this.data[y][x];
 | 
					 | 
				
			||||||
                switch(piece.type) {
 | 
					 | 
				
			||||||
                    case Empty, Rock, NPC, InfinityStone, Thanos -> {
 | 
					 | 
				
			||||||
                        score += 0;
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    case Character -> {
 | 
					 | 
				
			||||||
                        float nearby = 0;
 | 
					 | 
				
			||||||
                        for(int x2 = 0; x2 < this.data[0].length; x2++) {
 | 
					 | 
				
			||||||
                            for(int y2 = 0; y2 < this.data.length; y2++) {
 | 
					 | 
				
			||||||
                                if(this.data[y2][x2].type == PieceType.InfinityStone) {
 | 
					 | 
				
			||||||
                                    nearby += (1f / new IntVector2(x2, y2).distance(current)) * 3f;
 | 
					 | 
				
			||||||
                                }
 | 
					 | 
				
			||||||
                            }
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                        float result = nearby + piece.inventory.size() + ((float)piece.hp.getValue() / (float)piece.hp.getMax()) * 2f;
 | 
					 | 
				
			||||||
                        if(piece.id.type == origin) {
 | 
					 | 
				
			||||||
                            score += result;
 | 
					 | 
				
			||||||
                        }else {
 | 
					 | 
				
			||||||
                            score -= result;
 | 
					 | 
				
			||||||
                        }
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return score;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected int calculateHash() {
 | 
					 | 
				
			||||||
        return Objects.hash(super.hashCode(), data);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private boolean lineOfSight(IntVector2 a, IntVector2 b) {
 | 
					 | 
				
			||||||
        for(IntVector2 pos: GameLogic.rasterize(a, b, false, false)) {
 | 
					 | 
				
			||||||
            if(this.data[pos.getY()][pos.getX()].type != PieceType.Empty) {
 | 
					 | 
				
			||||||
                return false;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return true;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,157 +0,0 @@
 | 
				
			|||||||
package uulm.teamname.marvelous.gamelibrary.ai;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.entities.EntityID;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.entities.EntityType;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.gamelogic.GameStateView;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
import java.util.HashMap;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class BoardAnalyzer {
 | 
					 | 
				
			||||||
    private final Board origin;
 | 
					 | 
				
			||||||
    private final EntityType player;
 | 
					 | 
				
			||||||
    private final HashMap<Integer, Float> scoreCache = new HashMap<>();
 | 
					 | 
				
			||||||
    private final HashMap<Integer, ArrayList<Action>> actionCache = new HashMap<>();
 | 
					 | 
				
			||||||
    private Action bestAction = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public BoardAnalyzer(GameStateView state, EntityID turn) {
 | 
					 | 
				
			||||||
        this.origin = Board.generate(state, turn);
 | 
					 | 
				
			||||||
        this.player = turn.type;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Action analyze(GameStateView state) {
 | 
					 | 
				
			||||||
        Node tree = new Node(origin, new Action(ActionType.None));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        int maxDepth = 2;
 | 
					 | 
				
			||||||
        int depth = 0;
 | 
					 | 
				
			||||||
        long startTime = System.nanoTime();
 | 
					 | 
				
			||||||
        while(System.nanoTime() - startTime <= 1000 * 1000 * 1000) {
 | 
					 | 
				
			||||||
            expandTree(tree, state);
 | 
					 | 
				
			||||||
            depth++;
 | 
					 | 
				
			||||||
            if(depth > maxDepth) {
 | 
					 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        alphaBetaMax(tree, Float.MIN_VALUE, Float.MAX_VALUE, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(bestAction != null) {
 | 
					 | 
				
			||||||
            return bestAction;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return new Action(ActionType.None);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private Float alphaBetaMax(Node root, Float a, Float b, boolean main) {
 | 
					 | 
				
			||||||
        if(!root.hasChildren()) {
 | 
					 | 
				
			||||||
            return calculateScore(root.board);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        Float w = a;
 | 
					 | 
				
			||||||
        for(Node child: root.getChildren()) {
 | 
					 | 
				
			||||||
            Float v;
 | 
					 | 
				
			||||||
            if(child.board.turn.type == child.board.origin) {
 | 
					 | 
				
			||||||
                v = alphaBetaMax(child, a, w, false);
 | 
					 | 
				
			||||||
            }else {
 | 
					 | 
				
			||||||
                v = alphaBetaMin(child, w, b);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(v > w) {
 | 
					 | 
				
			||||||
                w = v;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(w >= b) {
 | 
					 | 
				
			||||||
                if(main) {
 | 
					 | 
				
			||||||
                    bestAction = child.action;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                return w;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(main) {
 | 
					 | 
				
			||||||
                bestAction = child.action;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return w;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private Float alphaBetaMin(Node root, Float a, Float b) {
 | 
					 | 
				
			||||||
        if(!root.hasChildren()) {
 | 
					 | 
				
			||||||
            return calculateScore(root.board);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        Float w = b;
 | 
					 | 
				
			||||||
        for(Node child: root.getChildren()) {
 | 
					 | 
				
			||||||
            Float v;
 | 
					 | 
				
			||||||
            if(child.board.turn.type == child.board.origin) {
 | 
					 | 
				
			||||||
                v = alphaBetaMax(child, a, w, false);
 | 
					 | 
				
			||||||
            }else {
 | 
					 | 
				
			||||||
                v = alphaBetaMin(child, w, b);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(v < w) {
 | 
					 | 
				
			||||||
                w = v;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(w <= a) {
 | 
					 | 
				
			||||||
                return w;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return w;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private ArrayList<Node> getLeaves(Node root) {
 | 
					 | 
				
			||||||
        return getLeaves(root, new ArrayList<>());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private ArrayList<Node> getLeaves(Node root, ArrayList<Node> accumulator) {
 | 
					 | 
				
			||||||
        for(Node child: root.getChildren()) {
 | 
					 | 
				
			||||||
            if(child.hasChildren()) {
 | 
					 | 
				
			||||||
                getLeaves(child, accumulator);
 | 
					 | 
				
			||||||
            }else {
 | 
					 | 
				
			||||||
                accumulator.add(child);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return accumulator;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private void expandTree(Node root, GameStateView state) {
 | 
					 | 
				
			||||||
        if(!root.hasChildren()) {
 | 
					 | 
				
			||||||
            expandNode(root, state);
 | 
					 | 
				
			||||||
            return;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        for(Node child: root.getChildren()) {
 | 
					 | 
				
			||||||
            if(child.board.ended) {
 | 
					 | 
				
			||||||
                continue;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            if(child.hasChildren()) {
 | 
					 | 
				
			||||||
                expandTree(child, state);
 | 
					 | 
				
			||||||
            }else {
 | 
					 | 
				
			||||||
                expandNode(child, state);
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private void expandNode(Node origin, GameStateView state) {
 | 
					 | 
				
			||||||
        ArrayList<Action> actions = generateActions(origin.board, state);
 | 
					 | 
				
			||||||
        for(Action action: actions) {
 | 
					 | 
				
			||||||
            Board result = origin.board.applyAction(state, action);
 | 
					 | 
				
			||||||
            scoreCache.put(result.hashCode(), result.calculateScore());
 | 
					 | 
				
			||||||
            origin.addChild(result, action, result.calculateScore());
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private ArrayList<Action> generateActions(Board board, GameStateView state) {
 | 
					 | 
				
			||||||
        int hash = board.hashCode();
 | 
					 | 
				
			||||||
        if(actionCache.containsKey(hash)) {
 | 
					 | 
				
			||||||
            return actionCache.get(hash);
 | 
					 | 
				
			||||||
        }else {
 | 
					 | 
				
			||||||
            ArrayList<Action> result = board.generateActions(state);
 | 
					 | 
				
			||||||
            actionCache.put(hash, result);
 | 
					 | 
				
			||||||
            return result;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private Float calculateScore(Board board) {
 | 
					 | 
				
			||||||
        int hash = board.hashCode();
 | 
					 | 
				
			||||||
        if(scoreCache.containsKey(hash)) {
 | 
					 | 
				
			||||||
            return scoreCache.get(hash);
 | 
					 | 
				
			||||||
        }else {
 | 
					 | 
				
			||||||
            Float result = board.calculateScore();
 | 
					 | 
				
			||||||
            scoreCache.put(hash, result);
 | 
					 | 
				
			||||||
            return result;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,60 +0,0 @@
 | 
				
			|||||||
package uulm.teamname.marvelous.gamelibrary.ai;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.ArrayList;
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public class Node {
 | 
					 | 
				
			||||||
    public final Board board;
 | 
					 | 
				
			||||||
    public final Action action;
 | 
					 | 
				
			||||||
    public final Float score;
 | 
					 | 
				
			||||||
    private final List<Node> children = new ArrayList<>();
 | 
					 | 
				
			||||||
    private Node parent = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Node(Board board, Action action) {
 | 
					 | 
				
			||||||
        this.board = board;
 | 
					 | 
				
			||||||
        this.action = action;
 | 
					 | 
				
			||||||
        this.score = 0f;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Node(Board board, Action action, Float score) {
 | 
					 | 
				
			||||||
        this.board = board;
 | 
					 | 
				
			||||||
        this.action = action;
 | 
					 | 
				
			||||||
        this.score = score;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void addChild(Node child) {
 | 
					 | 
				
			||||||
        child.setParent(this);
 | 
					 | 
				
			||||||
        this.children.add(child);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void addChild(Board board, Action action) {
 | 
					 | 
				
			||||||
        this.addChild(new Node(board, action));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void addChild(Board board, Action action, Float score) {
 | 
					 | 
				
			||||||
        this.addChild(new Node(board, action, score));
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public void addChildren(List<Node> children) {
 | 
					 | 
				
			||||||
        for(Node t : children) {
 | 
					 | 
				
			||||||
            t.setParent(this);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.children.addAll(children);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public List<Node> getChildren() {
 | 
					 | 
				
			||||||
        return children;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public boolean hasChildren() {
 | 
					 | 
				
			||||||
        return !children.isEmpty();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private void setParent(Node parent) {
 | 
					 | 
				
			||||||
        this.parent = parent;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Node getParent() {
 | 
					 | 
				
			||||||
        return parent;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,91 +0,0 @@
 | 
				
			|||||||
package uulm.teamname.marvelous.gamelibrary.ai;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.entities.*;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.Arrays;
 | 
					 | 
				
			||||||
import java.util.HashSet;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Piece {
 | 
					 | 
				
			||||||
    public final PieceType type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public EntityID id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Stat hp;
 | 
					 | 
				
			||||||
    public Stat mp;
 | 
					 | 
				
			||||||
    public Stat ap;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public HashSet<StoneType> inventory;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public StoneType stone;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Piece(PieceType type) {
 | 
					 | 
				
			||||||
        this.type = type;
 | 
					 | 
				
			||||||
        this.id = null;
 | 
					 | 
				
			||||||
        this.hp = null;
 | 
					 | 
				
			||||||
        this.mp = null;
 | 
					 | 
				
			||||||
        this.ap = null;
 | 
					 | 
				
			||||||
        this.inventory = null;
 | 
					 | 
				
			||||||
        this.stone = null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Piece(PieceType type, EntityID id) {
 | 
					 | 
				
			||||||
        this.type = type;
 | 
					 | 
				
			||||||
        this.id = id;
 | 
					 | 
				
			||||||
        this.hp = null;
 | 
					 | 
				
			||||||
        this.mp = null;
 | 
					 | 
				
			||||||
        this.ap = null;
 | 
					 | 
				
			||||||
        this.inventory = null;
 | 
					 | 
				
			||||||
        this.stone = null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Piece(PieceType type, EntityID id, int hp, int maxHP) {
 | 
					 | 
				
			||||||
        this.type = type;
 | 
					 | 
				
			||||||
        this.id = id;
 | 
					 | 
				
			||||||
        this.hp = new Stat(StatType.HP, hp, maxHP);
 | 
					 | 
				
			||||||
        this.mp = null;
 | 
					 | 
				
			||||||
        this.ap = null;
 | 
					 | 
				
			||||||
        this.inventory = null;
 | 
					 | 
				
			||||||
        this.stone = null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Piece(PieceType type, EntityID id, StoneType stone) {
 | 
					 | 
				
			||||||
        this.type = type;
 | 
					 | 
				
			||||||
        this.id = id;
 | 
					 | 
				
			||||||
        this.hp = null;
 | 
					 | 
				
			||||||
        this.mp = null;
 | 
					 | 
				
			||||||
        this.ap = null;
 | 
					 | 
				
			||||||
        this.inventory = null;
 | 
					 | 
				
			||||||
        this.stone = stone;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Piece(PieceType type, EntityID id, int hp, int maxHP, int mp, int maxMP, int ap, int maxAP, StoneType[] inventory) {
 | 
					 | 
				
			||||||
        this.type = type;
 | 
					 | 
				
			||||||
        this.id = id;
 | 
					 | 
				
			||||||
        this.hp = new Stat(StatType.HP, hp, maxHP);
 | 
					 | 
				
			||||||
        this.mp = new Stat(StatType.MP, mp, maxMP);
 | 
					 | 
				
			||||||
        this.ap = new Stat(StatType.AP, ap, maxAP);
 | 
					 | 
				
			||||||
        this.inventory = new HashSet<>(Arrays.asList(inventory));
 | 
					 | 
				
			||||||
        this.stone = null;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private Piece(PieceType type, EntityID id, int hp, int maxHP, int mp, int maxMP, int ap, int maxAP, StoneType[] inventory, StoneType stone) {
 | 
					 | 
				
			||||||
        this.type = type;
 | 
					 | 
				
			||||||
        this.id = id;
 | 
					 | 
				
			||||||
        this.hp = new Stat(StatType.HP, hp, maxHP);
 | 
					 | 
				
			||||||
        this.mp = new Stat(StatType.MP, mp, maxMP);
 | 
					 | 
				
			||||||
        this.ap = new Stat(StatType.AP, ap, maxAP);
 | 
					 | 
				
			||||||
        this.inventory = new HashSet<>(Arrays.asList(inventory));
 | 
					 | 
				
			||||||
        this.stone = stone;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public Piece clone() {
 | 
					 | 
				
			||||||
        Piece clone = new Piece(type);
 | 
					 | 
				
			||||||
        clone.id = this.id != null ? this.id.clone() : null;
 | 
					 | 
				
			||||||
        clone.hp = this.hp != null ? new Stat(StatType.HP, this.hp.getValue(), this.hp.getMax()) : null;
 | 
					 | 
				
			||||||
        clone.mp = this.mp != null ? new Stat(StatType.MP, this.mp.getValue(), this.mp.getMax()) : null;
 | 
					 | 
				
			||||||
        clone.ap = this.ap != null ? new Stat(StatType.AP, this.ap.getValue(), this.ap.getMax()) : null;
 | 
					 | 
				
			||||||
        clone.inventory = this.inventory != null ? (HashSet<StoneType>)this.inventory.clone() : null;
 | 
					 | 
				
			||||||
        clone.stone = this.stone;
 | 
					 | 
				
			||||||
        return clone;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,11 +0,0 @@
 | 
				
			|||||||
package uulm.teamname.marvelous.gamelibrary.ai;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum PieceType {
 | 
					 | 
				
			||||||
    Empty,
 | 
					 | 
				
			||||||
    Rock,
 | 
					 | 
				
			||||||
    Character,
 | 
					 | 
				
			||||||
    InfinityStone,
 | 
					 | 
				
			||||||
    Thanos,
 | 
					 | 
				
			||||||
    NPC,
 | 
					 | 
				
			||||||
    Portal
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,95 +0,0 @@
 | 
				
			|||||||
package uulm.teamname.marvelous.gamelibrary.gamelogic;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import org.junit.jupiter.api.BeforeAll;
 | 
					 | 
				
			||||||
import org.junit.jupiter.api.Test;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.ai.AIClient;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.entities.EntityType;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.events.Event;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.json.JSON;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.messages.*;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.messages.client.*;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.messages.server.*;
 | 
					 | 
				
			||||||
import uulm.teamname.marvelous.gamelibrary.requests.*;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.List;
 | 
					 | 
				
			||||||
import java.util.Optional;
 | 
					 | 
				
			||||||
import java.util.concurrent.*;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class AITest extends BaseGameLogicTest {
 | 
					 | 
				
			||||||
    private static JSON json;
 | 
					 | 
				
			||||||
    private static ExecutorService executor;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private static GameInstance server;
 | 
					 | 
				
			||||||
    private static AIClient clientA;
 | 
					 | 
				
			||||||
    private static AIClient clientB;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @BeforeAll
 | 
					 | 
				
			||||||
    static void setUp() {
 | 
					 | 
				
			||||||
        generate();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        json = new JSON(characterConfig);
 | 
					 | 
				
			||||||
        executor = new SimpleErrorSensitiveThreadPoolExecutor();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        server = new GameInstance(partyConfig, characterConfig, scenarioConfig);
 | 
					 | 
				
			||||||
        clientA = new AIClient(EntityType.P1, partyConfig, characterConfig, scenarioConfig);
 | 
					 | 
				
			||||||
        clientB = new AIClient(EntityType.P2, partyConfig, characterConfig, scenarioConfig);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Test
 | 
					 | 
				
			||||||
    void main() throws InterruptedException {
 | 
					 | 
				
			||||||
        serverSend(server.startGame(player1Selection, player2Selection).toArray(new Event[0]));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Thread.sleep(2000);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private void clientSend(Request[] requests) {
 | 
					 | 
				
			||||||
        RequestMessage message = new RequestMessage();
 | 
					 | 
				
			||||||
        message.messages = requests;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Optional<String> data = json.stringify(message);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(data.isPresent()) {
 | 
					 | 
				
			||||||
            executor.submit(() -> serverReceive(data.get()));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private void clientReceive(String data) {
 | 
					 | 
				
			||||||
        Optional<BasicMessage> message = json.parse(data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(message.isPresent()) {
 | 
					 | 
				
			||||||
            Optional<List<Request>> resultA = clientA.handle(((EventMessage)message.get()).messages);
 | 
					 | 
				
			||||||
            Optional<List<Request>> resultB = clientB.handle(((EventMessage)message.get()).messages);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if(resultA.isPresent()) {
 | 
					 | 
				
			||||||
                executor.submit(() -> clientSend(resultA.get().toArray(new Request[0])));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if(resultB.isPresent()) {
 | 
					 | 
				
			||||||
                executor.submit(() -> clientSend(resultB.get().toArray(new Request[0])));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private void serverSend(Event[] events) {
 | 
					 | 
				
			||||||
        EventMessage message = new EventMessage();
 | 
					 | 
				
			||||||
        message.messages = events;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        Optional<String> data = json.stringify(message);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(data.isPresent()) {
 | 
					 | 
				
			||||||
            executor.submit(() -> clientReceive(data.get()));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private void serverReceive(String data) {
 | 
					 | 
				
			||||||
        Optional<BasicMessage> message = json.parse(data);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(message.isPresent()) {
 | 
					 | 
				
			||||||
            Optional<List<Event>> result = server.checkRequestsAndApply(((RequestMessage)message.get()).messages);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            if(result.isPresent()) {
 | 
					 | 
				
			||||||
                executor.submit(() -> serverSend(result.get().toArray(new Event[0])));
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,30 +0,0 @@
 | 
				
			|||||||
package uulm.teamname.marvelous.gamelibrary.gamelogic;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.concurrent.*;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
public final class SimpleErrorSensitiveThreadPoolExecutor extends ThreadPoolExecutor {
 | 
					 | 
				
			||||||
    public SimpleErrorSensitiveThreadPoolExecutor() {
 | 
					 | 
				
			||||||
        super(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    protected void afterExecute(Runnable r, Throwable t) {
 | 
					 | 
				
			||||||
        super.afterExecute(r, t);
 | 
					 | 
				
			||||||
        if (t == null && r instanceof Future<?>) {
 | 
					 | 
				
			||||||
            try {
 | 
					 | 
				
			||||||
                Future<?> future = (Future<?>) r;
 | 
					 | 
				
			||||||
                if (future.isDone()) {
 | 
					 | 
				
			||||||
                    future.get();
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            } catch (CancellationException ce) {
 | 
					 | 
				
			||||||
                t = ce;
 | 
					 | 
				
			||||||
            } catch (ExecutionException ee) {
 | 
					 | 
				
			||||||
                t = ee.getCause();
 | 
					 | 
				
			||||||
            } catch (InterruptedException ie) {
 | 
					 | 
				
			||||||
                Thread.currentThread().interrupt();
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (t != null) {
 | 
					 | 
				
			||||||
            t.printStackTrace();
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user