From c8719bf06393ee7e251170b62df00a8ca265f5a3 Mon Sep 17 00:00:00 2001 From: Jan Fic Date: Mon, 14 Feb 2022 13:50:55 -0500 Subject: [PATCH] added simple Heuristic Priority Bot --- .../games/computercombat/model/Player.java | 8 ++ .../computercombat/model/moves/Move.java | 15 +++- .../model/players/HeuristicBotPlayer.java | 80 +++++++++++++++++++ .../ExtraTurnHeuristicAnalyzer.java | 26 ++++++ .../heuristicanalyzers/HeuristicAnalyzer.java | 13 +++ .../games/computercombat/server/Server.java | 5 +- 6 files changed, 143 insertions(+), 4 deletions(-) create mode 100644 computercombat/core/src/com/janfic/games/computercombat/model/players/HeuristicBotPlayer.java create mode 100644 computercombat/core/src/com/janfic/games/computercombat/model/players/heuristicanalyzers/ExtraTurnHeuristicAnalyzer.java create mode 100644 computercombat/core/src/com/janfic/games/computercombat/model/players/heuristicanalyzers/HeuristicAnalyzer.java diff --git a/computercombat/core/src/com/janfic/games/computercombat/model/Player.java b/computercombat/core/src/com/janfic/games/computercombat/model/Player.java index fe710f7..23370d9 100644 --- a/computercombat/core/src/com/janfic/games/computercombat/model/Player.java +++ b/computercombat/core/src/com/janfic/games/computercombat/model/Player.java @@ -56,4 +56,12 @@ public void read(Json json, JsonValue jsonData) { this.uid = json.readValue("uid", String.class, jsonData); this.deck = json.readValue("deck", Deck.class, jsonData); } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Player) { + return ((Player) obj).getUID().equals(this.getUID()); + } + return super.equals(obj); + } } diff --git a/computercombat/core/src/com/janfic/games/computercombat/model/moves/Move.java b/computercombat/core/src/com/janfic/games/computercombat/model/moves/Move.java index 02c09b9..c5a066a 100644 --- a/computercombat/core/src/com/janfic/games/computercombat/model/moves/Move.java +++ b/computercombat/core/src/com/janfic/games/computercombat/model/moves/Move.java @@ -23,13 +23,16 @@ public abstract class Move implements Json.Serializable { protected String playerUID; + private double value; public Move() { this.playerUID = null; + this.value = 0; } public Move(String playerUID) { this.playerUID = playerUID; + this.value = 0; } public abstract List doMove(MatchState state); @@ -38,6 +41,14 @@ public String getPlayerUID() { return playerUID; } + public void setValue(double value) { + this.value = value; + } + + public double getValue() { + return value; + } + @Override public void read(Json json, JsonValue jsonData) { this.playerUID = json.readValue("playerUID", String.class, jsonData); @@ -50,7 +61,9 @@ public void write(Json json) { } /** - * Checks and calculates if there are any matched but uncollected components on the board. + * Checks and calculates if there are any matched but uncollected components + * on the board. + * * @param state - state to check * @param move move that caused this new state * @return a list of MoveResults diff --git a/computercombat/core/src/com/janfic/games/computercombat/model/players/HeuristicBotPlayer.java b/computercombat/core/src/com/janfic/games/computercombat/model/players/HeuristicBotPlayer.java new file mode 100644 index 0000000..ab73823 --- /dev/null +++ b/computercombat/core/src/com/janfic/games/computercombat/model/players/HeuristicBotPlayer.java @@ -0,0 +1,80 @@ +package com.janfic.games.computercombat.model.players; + +import com.janfic.games.computercombat.model.Deck; +import com.janfic.games.computercombat.model.GameRules; +import com.janfic.games.computercombat.model.Player; +import com.janfic.games.computercombat.model.match.MatchResults; +import com.janfic.games.computercombat.model.match.MatchState; +import com.janfic.games.computercombat.model.moves.Move; +import com.janfic.games.computercombat.model.moves.MoveResult; +import com.janfic.games.computercombat.model.players.heuristicanalyzers.ExtraTurnHeuristicAnalyzer; +import com.janfic.games.computercombat.model.players.heuristicanalyzers.HeuristicAnalyzer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * + * @author janfc + */ +public class HeuristicBotPlayer extends Player { + + MatchState currentState; + + List priorityList; + + public HeuristicBotPlayer() { + } + + public HeuristicBotPlayer(String uid, Deck deck) { + super(uid, deck); + } + + @Override + public void beginMatch(MatchState state, Player opponent) { + this.currentState = state; + this.priorityList = new ArrayList<>(); + this.priorityList.add(new ExtraTurnHeuristicAnalyzer()); + } + + @Override + public Move getMove() { + List moves = GameRules.getAvailableMoves(currentState); + Collections.shuffle(moves); + + for (Move move : moves) { + List results = GameRules.makeMove(currentState, move); + double totalScore = 0; + for (int i = 0; i < priorityList.size(); i++) { + HeuristicAnalyzer analyzer = priorityList.get(i); + double baseScore = analyzer.analyze(results); + double priorityScalar = Math.pow(2, i); + double priorityScore = priorityScalar * baseScore; + totalScore += priorityScore; + } + move.setValue(totalScore); + } + + moves.sort(new MoveValueComparator()); + + return moves.get(0); + } + + @Override + public void updateState(List state) { + this.currentState = state.get(state.size() - 1).getNewState(); + } + + @Override + public void gameOver(MatchResults results) { + } + + public class MoveValueComparator implements Comparator { + + @Override + public int compare(Move a, Move b) { + return (int) Math.ceil(b.getValue() - a.getValue()); + } + } +} diff --git a/computercombat/core/src/com/janfic/games/computercombat/model/players/heuristicanalyzers/ExtraTurnHeuristicAnalyzer.java b/computercombat/core/src/com/janfic/games/computercombat/model/players/heuristicanalyzers/ExtraTurnHeuristicAnalyzer.java new file mode 100644 index 0000000..6764d00 --- /dev/null +++ b/computercombat/core/src/com/janfic/games/computercombat/model/players/heuristicanalyzers/ExtraTurnHeuristicAnalyzer.java @@ -0,0 +1,26 @@ +package com.janfic.games.computercombat.model.players.heuristicanalyzers; + +import com.janfic.games.computercombat.model.match.MatchState; +import com.janfic.games.computercombat.model.moves.MoveResult; +import java.util.List; + +/** + * Analyzes a move's results to determine if an extra-move has been gained. + * + * @author janfc + */ +public class ExtraTurnHeuristicAnalyzer extends HeuristicAnalyzer { + + @Override + public float analyze(List results) { + float extraMove = 0; + + MatchState lastState = results.get(results.size() - 1).getNewState(); + MatchState firstState = results.get(0).getOldState(); + boolean gainedExtra = lastState.currentPlayerMove.equals(firstState.currentPlayerMove); + + extraMove = gainedExtra ? 1 : 0; + + return extraMove; + } +} diff --git a/computercombat/core/src/com/janfic/games/computercombat/model/players/heuristicanalyzers/HeuristicAnalyzer.java b/computercombat/core/src/com/janfic/games/computercombat/model/players/heuristicanalyzers/HeuristicAnalyzer.java new file mode 100644 index 0000000..ac0882f --- /dev/null +++ b/computercombat/core/src/com/janfic/games/computercombat/model/players/heuristicanalyzers/HeuristicAnalyzer.java @@ -0,0 +1,13 @@ +package com.janfic.games.computercombat.model.players.heuristicanalyzers; + +import com.janfic.games.computercombat.model.moves.MoveResult; +import java.util.List; + +/** + * + * @author janfc + */ +public abstract class HeuristicAnalyzer { + + public abstract float analyze(List results); +} diff --git a/computercombat/server/src/com/janfic/games/computercombat/server/Server.java b/computercombat/server/src/com/janfic/games/computercombat/server/Server.java index b3a31c2..dc5131f 100644 --- a/computercombat/server/src/com/janfic/games/computercombat/server/Server.java +++ b/computercombat/server/src/com/janfic/games/computercombat/server/Server.java @@ -10,7 +10,7 @@ import com.badlogic.gdx.net.Socket; import com.badlogic.gdx.utils.Json; import com.janfic.games.computercombat.model.*; -import com.janfic.games.computercombat.model.players.BotPlayer; +import com.janfic.games.computercombat.model.players.HeuristicBotPlayer; import com.janfic.games.computercombat.model.players.HumanPlayer; import com.janfic.games.computercombat.network.Message; import com.janfic.games.computercombat.network.Type; @@ -19,7 +19,6 @@ import java.io.*; import java.util.*; import java.util.concurrent.CompletableFuture; -import java.util.function.Supplier; import software.amazon.awssdk.services.cognitoidentityprovider.model.UsernameExistsException; /** @@ -305,7 +304,7 @@ public void run() { if (matches.size() < MAX_MATCHES && raidQueue.size() > 0) { MatchClient a = raidQueue.get(0); Player playerA = new HumanPlayer(a.getProfile().getUID(), a); - Player botPlayer = new BotPlayer("botUID", a.getDeck()); + Player botPlayer = new HeuristicBotPlayer("botUID", a.getDeck()); ServerMatchRoom room = new ServerMatchRoom(playerA, botPlayer); try { Message message2 = new Message(Type.FOUND_MATCH, "RAID BOT");