cleanup: remove moved code

This commit is contained in:
punchready 2021-07-01 15:02:39 +02:00
parent a289fee059
commit 7fffe2efbb
11 changed files with 0 additions and 1149 deletions

View File

@ -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;
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}

View File

@ -1,11 +0,0 @@
package uulm.teamname.marvelous.gamelibrary.ai;
enum ActionType {
None,
Move,
MeleeAttack,
RangedAttack,
UseStone,
GiveStone,
EndTurn
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -1,11 +0,0 @@
package uulm.teamname.marvelous.gamelibrary.ai;
enum PieceType {
Empty,
Rock,
Character,
InfinityStone,
Thanos,
NPC,
Portal
}

View File

@ -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])));
}
}
}
}

View File

@ -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();
}
}
}