diff --git a/src/controllers/Manager.java b/src/controllers/Manager.java index dda01ab..52e1ec2 100644 --- a/src/controllers/Manager.java +++ b/src/controllers/Manager.java @@ -150,7 +150,6 @@ public static Input getInput() { } public static String getAIMove() { - playingMatch.getPlayer2().decide(); return playingMatch.getPlayer2().getDecision(); } @@ -190,7 +189,7 @@ public static void setMatchData(boolean isAIMode, int gameMode, String username) if (!isOpponentNull()) { Account opponent; if (isAIMode) { - opponent = Account.getAIAccount(); + opponent = AI.getAIAccount(); } else opponent = Account.getAccounts().get(username); @@ -211,6 +210,9 @@ public static void setMatchData(boolean isAIMode, int gameMode, String username) opponentUsername = ""; } playingMatch.setAIMode(isAIMode); + if (isAIMode) { + ((AI) opponent).setMatch(playingMatch); + } } } @@ -335,4 +337,8 @@ public static List getItem(List cards) { card -> (UsableItem) card) .collect(Collectors.toList()); } + + public static void setMapFlags(int result) { + playingMatch.setFlagsInMap(result); + } } diff --git a/src/models/AI.java b/src/models/AI.java index 40a477f..11fbf68 100644 --- a/src/models/AI.java +++ b/src/models/AI.java @@ -1,5 +1,201 @@ package models; -public class AI { +import controllers.Manager; +import models.map.Cell; +import models.map.Map; +import models.match.Match; +import views.Output; +import java.util.*; + +public class AI extends Account { + + Match match; + private Queue decisions = new LinkedList<>(); + /// state[distanceToHero][oppHealth][myHealth][action] + int[][][][] state = new int[10][10][10][3]; + private final int ACTIONS_NUMBER = 3; + int[] lastState = new int[3]; + + public AI(String username, String password) { + super(username, password); + } + + private int distanceToOppHero() { + int distance = 0; + try { + distance = Cell.manhattanDistance(match.getPlayer1().getHero().getCell(), + match.getPlayer2().getHero().getCell()) - 1; + if (distance >= 9) + distance = 9; + } catch (Exception ignored) { + Output.err("Ignored in AI"); + } + return distance; + } + + private int getHealth() { + int health = 0; + try { + health = match.getPlayer2().getHero().getCurrentHealth() / 5; + if (health >= 9) + health = 9; + } catch (Exception ignored) { + Output.err("Ignored in AI"); + } + return health; + } + + private int getOppHealth() { + int health = 0; + try { + health = match.getPlayer1().getHero().getCurrentHealth() / 5; + if (health >= 9) + health = 9; + } catch (Exception ignored) { + Output.err("Ignored in AI"); + } + return health; + } + + int t = 0; + + public void decide() { + reward(); + int distance = lastState[0] = distanceToOppHero(); + int myHealth = lastState[1] = getHealth(); + int oppHealth = lastState[2] = getOppHealth(); + int max = 0; + for (int i = 0; i < ACTIONS_NUMBER; i++) { + max = Math.max(max, state[distance][oppHealth][myHealth][i]); + } + if (max < 100) { + chooseAction(new Random().nextInt() % 3); + return; + } + for (int i = 0; i < ACTIONS_NUMBER; i++) { + if (state[distance][oppHealth][myHealth][i] == max) { + chooseAction(i); + return; + } + } +// if (t % 2 == 0) +// this.decision = "show hand"; +// else +// this.decision = "end turn"; +// t = (t + 1) % 2; + } + + private void reward() { + + } + + private void chooseAction(int action) { + switch (action) { + case 0: + insertCard(); + break; + case 1: + moveCard(); + break; + case 2: + attack(); + break; + default: + decisions.add("end turn"); + } + } + + private void attack() { + selectCard(); + try { + decisions.add("attack " + match.getPlayer1().getHero().getID()); + } catch (Player.HeroDeadException e) { + Output.err("ignored in attack in AI"); + } + } + + private void insertCard() { + decisions.add("insert " + match.getPlayer2().getHand().getCards().get(Match.random(0, 4)).getID() + " in " + + Match.random(1, Map.ROW_NUMBER) + ", " + Match.random(1, Map.COLUMN_NUMBER)); + } + + private void selectCard() { + try { + decisions.add("select " + match.getPlayer2().getHero().getID()); + } catch (Player.HeroDeadException e) { + Output.err("ignored in insertCard in AI"); + } + } + + private void moveCard() { + selectCard(); + decisions.add("move to " + Match.random(1, Map.ROW_NUMBER) + ", " + Match.random(1, Map.COLUMN_NUMBER)); + } + + + public String getDecision() { + if (match.getPlayer2().getMana() < 2) + return "end turn"; + if (decisions.size() == 0) + decide(); + return decisions.poll(); + } + + public void setMatch(Match playingMatch) { + this.match = playingMatch; + } + + public static AI getAIAccount() { + AI aiAccount = new AI("AI", "password"); + try { + Shop.getInstance().buy(aiAccount, "rostam"); + Shop.getInstance().buy(aiAccount, "fire dragon"); + Shop.getInstance().buy(aiAccount, "eagle"); + Shop.getInstance().buy(aiAccount, "Hog Head Demon"); + Shop.getInstance().buy(aiAccount, "Persian Swordsman"); + Shop.getInstance().buy(aiAccount, "Persian Horse Rider"); + Shop.getInstance().buy(aiAccount, "Persian Horse Rider"); + Shop.getInstance().buy(aiAccount, "Persian Horse Rider"); + Shop.getInstance().buy(aiAccount, "Persian Horse Rider"); + Shop.getInstance().buy(aiAccount, "Persian Champion"); + Shop.getInstance().buy(aiAccount, "Persian Champion"); + Shop.getInstance().buy(aiAccount, "Turan Archer"); + Shop.getInstance().buy(aiAccount, "Turan Archer"); + Shop.getInstance().buy(aiAccount, "Turan Wand"); + Shop.getInstance().buy(aiAccount, "Turan Wand"); + Shop.getInstance().buy(aiAccount, "persian horse rider"); + Shop.getInstance().buy(aiAccount, "persian horse rider"); + Shop.getInstance().buy(aiAccount, "persian horse rider"); + Shop.getInstance().buy(aiAccount, "persian horse rider"); + Shop.getInstance().buy(aiAccount, "persian horse rider"); + Shop.getInstance().buy(aiAccount, "persian horse rider"); + aiAccount.addDeck(new Deck("AIDeck")); + Deck deck = aiAccount.getDeck("AIDeck"); + Manager.addCardToDeck(aiAccount, deck, "rostam"); + Manager.addCardToDeck(aiAccount, deck, "fire dragon"); + Manager.addCardToDeck(aiAccount, deck, "eagle"); + Manager.addCardToDeck(aiAccount, deck, "Hog Head Demon"); + Manager.addCardToDeck(aiAccount, deck, "Persian Swordsman"); + Manager.addCardToDeck(aiAccount, deck, "Persian Horse Rider"); + Manager.addCardToDeck(aiAccount, deck, "Persian Horse Rider"); + Manager.addCardToDeck(aiAccount, deck, "Persian Horse Rider"); + Manager.addCardToDeck(aiAccount, deck, "Persian Horse Rider"); + Manager.addCardToDeck(aiAccount, deck, "Persian Champion"); + Manager.addCardToDeck(aiAccount, deck, "Persian Champion"); + Manager.addCardToDeck(aiAccount, deck, "Turan Archer"); + Manager.addCardToDeck(aiAccount, deck, "Turan Archer"); + Manager.addCardToDeck(aiAccount, deck, "Turan Wand"); + Manager.addCardToDeck(aiAccount, deck, "Turan Wand"); + Manager.addCardToDeck(aiAccount, deck, "persian horse rider"); + Manager.addCardToDeck(aiAccount, deck, "persian horse rider"); + Manager.addCardToDeck(aiAccount, deck, "persian horse rider"); + Manager.addCardToDeck(aiAccount, deck, "persian horse rider"); + Manager.addCardToDeck(aiAccount, deck, "persian horse rider"); + aiAccount.setMainDeck(deck); + } catch (Exception e) { + Output.err(e); + } + return aiAccount; + } } diff --git a/src/models/Account.java b/src/models/Account.java index 05e867c..3cb8d09 100644 --- a/src/models/Account.java +++ b/src/models/Account.java @@ -17,58 +17,7 @@ public class Account { private int drake = 15000; private int winCount = 0; - public static Account getAIAccount() { - Account account = new Account("AI", "password"); - try { - Shop.getInstance().buy(account, "rostam"); - Shop.getInstance().buy(account, "fire dragon"); - Shop.getInstance().buy(account, "eagle"); - Shop.getInstance().buy(account, "Hog Head Demon"); - Shop.getInstance().buy(account, "Persian Swordsman"); - Shop.getInstance().buy(account, "Persian Horse Rider"); - Shop.getInstance().buy(account, "Persian Horse Rider"); - Shop.getInstance().buy(account, "Persian Horse Rider"); - Shop.getInstance().buy(account, "Persian Horse Rider"); - Shop.getInstance().buy(account, "Persian Champion"); - Shop.getInstance().buy(account, "Persian Champion"); - Shop.getInstance().buy(account, "Turan Archer"); - Shop.getInstance().buy(account, "Turan Archer"); - Shop.getInstance().buy(account, "Turan Wand"); - Shop.getInstance().buy(account, "Turan Wand"); - Shop.getInstance().buy(account, "persian horse rider"); - Shop.getInstance().buy(account, "persian horse rider"); - Shop.getInstance().buy(account, "persian horse rider"); - Shop.getInstance().buy(account, "persian horse rider"); - Shop.getInstance().buy(account, "persian horse rider"); - Shop.getInstance().buy(account, "persian horse rider"); - account.addDeck(new Deck("AIDeck")); - Deck deck = account.getDeck("AIDeck"); - Manager.addCardToDeck(account, deck, "rostam"); - Manager.addCardToDeck(account, deck, "fire dragon"); - Manager.addCardToDeck(account, deck, "eagle"); - Manager.addCardToDeck(account, deck, "Hog Head Demon"); - Manager.addCardToDeck(account, deck, "Persian Swordsman"); - Manager.addCardToDeck(account, deck, "Persian Horse Rider"); - Manager.addCardToDeck(account, deck, "Persian Horse Rider"); - Manager.addCardToDeck(account, deck, "Persian Horse Rider"); - Manager.addCardToDeck(account, deck, "Persian Horse Rider"); - Manager.addCardToDeck(account, deck, "Persian Champion"); - Manager.addCardToDeck(account, deck, "Persian Champion"); - Manager.addCardToDeck(account, deck, "Turan Archer"); - Manager.addCardToDeck(account, deck, "Turan Archer"); - Manager.addCardToDeck(account, deck, "Turan Wand"); - Manager.addCardToDeck(account, deck, "Turan Wand"); - Manager.addCardToDeck(account, deck, "persian horse rider"); - Manager.addCardToDeck(account, deck, "persian horse rider"); - Manager.addCardToDeck(account, deck, "persian horse rider"); - Manager.addCardToDeck(account, deck, "persian horse rider"); - Manager.addCardToDeck(account, deck, "persian horse rider"); - account.setMainDeck(deck); - } catch (Exception e) { - Output.err(e); - } - return account; - } + public int getDrake() { return drake; diff --git a/src/models/Player.java b/src/models/Player.java index 3928452..a763e8c 100644 --- a/src/models/Player.java +++ b/src/models/Player.java @@ -3,16 +3,15 @@ import models.cards.Attacker; import models.cards.Card; import models.cards.Hero; -import models.cards.Minion; import models.cards.spell.Spell; import models.items.CollectableItem; +import models.items.Flag; import models.items.Item; import models.map.Cell; import views.Error; import views.Input; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.stream.Collectors; @@ -21,13 +20,12 @@ public class Player { private Deck deck; private Hand hand = new Hand(); private Card selectedCard; - private int flags; + private int flagsNumber; private List collectedItems = new ArrayList<>(); private ArrayList graveYard; private ArrayList activeCards = new ArrayList<>(); private int mana; private Input input; - private String decision; private CollectableItem selectedCollectableItem; public Account getAccount() { @@ -51,6 +49,11 @@ public Player(Account account) { this.setNextCard(); } + public String getDecision() { + AI ai = (AI)account; + return ai.getDecision(); + } + public ArrayList getGraveYard() { return graveYard; } @@ -95,7 +98,7 @@ public Deck getDeck() { } public void incrementFlags() { - this.flags += flags; + this.flagsNumber += flagsNumber; } public void setCollectedItems(Item collectedItems) { @@ -149,18 +152,6 @@ public Attacker getActiveCard(String cardID) throws Collection.CardNotFoundExcep throw new Collection.CardNotFoundException("Card not found with this ID"); } } - int t = 0; - public void decide() { - if (t % 2 == 0) - this.decision = "show hand"; - else - this.decision = "end turn"; - t = (t + 1) % 2; - } - - public String getDecision() { - return decision; - } public void selectCard(Card card) { this.selectedCard = card; @@ -199,6 +190,19 @@ public boolean collectableItemIsSelected() { return selectedCollectableItem != null; } + public boolean hasFlag() { + return this.flagsNumber > 0; + } + + public List getFlags() { + return activeCards.stream().map(Attacker::getFlag).collect(Collectors.toList()); + } + + public int getFlagsNumber() { + return flagsNumber; + } + + public static class NotEnoughManaException extends Exception { public NotEnoughManaException(String message) { super(message); diff --git a/src/models/items/Flag.java b/src/models/items/Flag.java index 152cc36..4eb268e 100644 --- a/src/models/items/Flag.java +++ b/src/models/items/Flag.java @@ -19,7 +19,7 @@ public int getTokenTurn() { return tokenTurn; } - public boolean isGotten() { + public boolean isToken() { return owner != null; } diff --git a/src/models/map/Cell.java b/src/models/map/Cell.java index 4c4afb3..e79cdc9 100644 --- a/src/models/map/Cell.java +++ b/src/models/map/Cell.java @@ -2,12 +2,14 @@ import models.cards.Attacker; import models.cards.Card; +import models.items.Flag; import models.items.Item; public class Cell { private int x, y; private Item item; private Attacker attacker; + private Flag flag; public Cell(int x, int y) { this.x = x; @@ -61,4 +63,12 @@ public void addCard(Attacker attacker) { public String toString() { return "(" + x + ", " + y + ")"; } + + public void setFlag(Flag flag) { + this.flag = flag; + } + + public boolean hasFlag() { + return flag != null; + } } diff --git a/src/models/map/Map.java b/src/models/map/Map.java index 9ba59f5..ab4bcd7 100644 --- a/src/models/map/Map.java +++ b/src/models/map/Map.java @@ -8,6 +8,7 @@ import models.cards.Minion; import models.cards.spell.Spell; import models.cards.spell.TargetType; +import models.items.Flag; import views.Error; import java.util.ArrayList; @@ -45,9 +46,7 @@ public String toString() { String username2 = null; for (int i = 0; i < 5; i++) { for (int j = 0; j < 9; j++) { - if (cells[i][j].getAttacker() == null) - stringBuilder.append(" _ "); - else { + if (cells[i][j].getAttacker() != null) { if (username1 == null) username1 = cells[i][j].getAttacker().getUsername(); if (username2 == null && username1 != null && !cells[i][j].getAttacker().getUsername().equals(username1)) @@ -58,7 +57,11 @@ public String toString() { else cardPrefix = '-'; stringBuilder.append(String.format("%c%02d", cardPrefix, cells[i][j].getAttacker().getId())); - } + } else if (cells[i][j].hasFlag()) { + stringBuilder.append("F"); + } else + stringBuilder.append(" _ "); + } stringBuilder.append("\n"); } @@ -162,6 +165,10 @@ private List getEffectCells(Spell spell, Cell cell) throws InvalidTargetCe throw new InvalidTargetCellException(); } + public void setFlag(int x, int y) { + cells[x][y].setFlag(new Flag()); + } + public class InvalidCellException extends Exception { public InvalidCellException(String message) { super(message); diff --git a/src/models/match/Match.java b/src/models/match/Match.java index b7ec2ff..451571d 100644 --- a/src/models/match/Match.java +++ b/src/models/match/Match.java @@ -10,10 +10,8 @@ import models.map.Cell; import models.map.Map; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; +import java.lang.reflect.MalformedParameterizedTypeException; +import java.util.*; import java.util.stream.Collector; import java.util.stream.Collectors; @@ -71,6 +69,22 @@ private void turnPreparing(Player player) { ); } + public static int random(int min, int max) { + return (int)(Math.random() * ((max - min) + 1)) + min ; + } + + public void setFlagsInMap(int flagsCount) { + if (flagsCount % 2 == 1) { + map.setFlag(random(1, Map.ROW_NUMBER), Map.COLUMN_NUMBER / 2 + 1); + for (int i = 0; i < 2; i++) { + for (int j = 0; j < flagsCount / 2; j++) { + map.setFlag(random(1, Map.ROW_NUMBER), (int) Math.ceil(1.0 * Map.COLUMN_NUMBER / 2) * i + + random(1, Map.COLUMN_NUMBER / 2)); + } + } + } + } + public void setTurn() { getActivePlayer().setMana(turn / 2 + 2); turnPreparing(players[0]); diff --git a/src/models/match/MultiFlagMatch.java b/src/models/match/MultiFlagMatch.java index 2b203e9..bd990e6 100644 --- a/src/models/match/MultiFlagMatch.java +++ b/src/models/match/MultiFlagMatch.java @@ -1,10 +1,8 @@ package models.match; import models.Account; -import models.Collection; import models.Player; import models.items.Flag; -import models.map.Cell; import java.util.ArrayList; import java.util.List; @@ -22,7 +20,10 @@ public void setFlags() { @Override public Player getWinner() { - + for (int i = 0; i < PLAYERS_COUNT; i++) { + if(players[i].getFlags().size() >= 1.*flags.size()/2) + return players[i]; + } return null; } @@ -31,7 +32,7 @@ public String getInfo() { StringBuilder result = new StringBuilder(); for (int i = 0; i < flags.size(); i++) { Flag flag = flags.get(i); - if (flag.isGotten()) { + if (flag.isToken()) { result.append(flag.getName()).append(" is token by attacker ").append(flag.getOwner().getName()).append(" of player number ").append(flag.getTokenTurn() % 2 + 1); } else { result.append(flag.getName()).append(" is not token."); diff --git a/src/models/match/SingleFlagMatch.java b/src/models/match/SingleFlagMatch.java index d704745..6e408a3 100644 --- a/src/models/match/SingleFlagMatch.java +++ b/src/models/match/SingleFlagMatch.java @@ -1,7 +1,6 @@ package models.match; import models.Account; -import models.Collection; import models.Player; import models.items.Flag; @@ -17,14 +16,20 @@ public SingleFlagMatch(Account account1 , Account account2) { @Override public Player getWinner() { - + for (int i = 0; i < PLAYERS_COUNT; i++) { + if(!players[i].hasFlag()) + continue; + if(getTurn() - players[i].getFlags().get(0).getTokenTurn() >= WINNING_TURN ) { + return players[i]; + } + } return null; } @Override public String getInfo() { String result = "Flag is in " + flag.getCell() + " cell and "; - if(flag.isGotten()) + if(flag.isToken()) result += "in hand of player number " + (flag.getTokenTurn() % 2 + 1) + " attacker " + flag.getOwner().getName() + "."; diff --git a/src/views/menus/PreBattleMenu.java b/src/views/menus/PreBattleMenu.java index 6fe8794..24efa3b 100644 --- a/src/views/menus/PreBattleMenu.java +++ b/src/views/menus/PreBattleMenu.java @@ -64,6 +64,23 @@ public void handleMenu() { result = askQuestion("Select Game Mode:", "Death match", "Multi flag mode", "Single flag mode"); gameMode = result + 1; } + if(result > 1){ + + if (result == 2) + result = 1; + if (result == 3) { + Output.log("How many flags do you want to have?(between 2 and 9"); + result = 0; + do { + try { + result = Integer.parseInt(Input.getString("")); + } catch (Exception ignored) {} + if(!(result < 2 || result > 9)) + Output.log("Enter a valid number !"); + } while (result < 2 || result > 9); + } + Manager.setMapFlags(result); + } String opponentName = ""; if(!AIMode) {