From 37d9f8478717cd6490d91e8dfce3e0a68991f498 Mon Sep 17 00:00:00 2001 From: Benedikt Galbavy Date: Sun, 21 Jan 2024 01:44:37 +0100 Subject: [PATCH] finished fight logic ~2h work --- .../nanopenguin/mtcg/application/Battle.java | 164 ++++++++++++++++-- .../mtcg/application/Combatant.java | 2 +- 2 files changed, 149 insertions(+), 17 deletions(-) diff --git a/src/main/java/at/nanopenguin/mtcg/application/Battle.java b/src/main/java/at/nanopenguin/mtcg/application/Battle.java index aefdebe..8874fd0 100644 --- a/src/main/java/at/nanopenguin/mtcg/application/Battle.java +++ b/src/main/java/at/nanopenguin/mtcg/application/Battle.java @@ -2,16 +2,25 @@ package at.nanopenguin.mtcg.application; import at.nanopenguin.mtcg.Pair; import at.nanopenguin.mtcg.application.service.schemas.Card; -import lombok.Getter; -import lombok.Setter; +import lombok.*; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.Random; public class Battle { - private record RoundResult(String winnerName, Card winnerCard, String loserName, Card loserCard, boolean draw) {}; + + @RequiredArgsConstructor + private enum ElementMod { + HALF(0.5), + NONE(1), + DOUBLE(2); + + public final double percentMod; + } + private record FightDTO(Combatant player, Card card) {}; + private record RoundResult(FightDTO winner, FightDTO loser, boolean draw, ElementMod winnerMod, ElementMod loserMod) {}; private Pair combatants; @Getter private volatile List log = new ArrayList<>(); @@ -27,28 +36,151 @@ public class Battle { } public void start() throws SQLException { + boolean leftWins; + int round = 0; do { - this.playRound(); - } while (combatants.left().deckSize() > 0 && combatants.right().deckSize() > 0); + this.playRound(++round); + if (round == 100) return; // don't update stats on draw + + System.out.println(combatants.left().deckSize() + " - " + combatants.right().deckSize() ); + } while ((leftWins = combatants.left().deckSize() > 0) && combatants.right().deckSize() > 0); - // placeholder - boolean leftWins = new Random().nextBoolean(); this.combatants.left().updateStats(leftWins); this.combatants.right().updateStats(!leftWins); } - private void playRound() { - Pair cards = new Pair<>(this.combatants.left().getCard(), this.combatants.right().getCard()); - //RoundResult result = this.fight(cards.left(), cards.right()); - //this.log.add(""); + private void playRound(int round) { + RoundResult result = this.fight( + new FightDTO( + this.combatants.left(), + this.combatants.left().getAndRemoveCard()), + new FightDTO( + this.combatants.right(), + this.combatants.right().getAndRemoveCard())); + + this.log.add(this.createCombatString(round, result)); + + result.winner().player().addCard( // return card to winner deck + result.winner().card()); + + if (result.draw()) { + result.loser().player().addCard( // on draw both players get their card + result.loser().card()); + return; + } + + result.winner.player().addCard( // on lose winner gets losers card to deck + result.loser().card()); } - private boolean fight(Card left, Card right) { - return true; + private boolean isImmune(Card defend, Card attack) { + if (defend.name().equals("Dragon") && attack.name().endsWith("Goblin")) return true; + if (defend.name().equals("Wizzard") && attack.name().equals("Ork")) return true; + if (defend.name().equals("WaterSpell") && attack.name().equals("Knight")) return true; + if (defend.name().equals("Kraken") && attack.name().endsWith("Spell")) return true; + if (defend.name().equals("FireElf") && attack.name().equals("Dragon")) return true; + + return false; } - private String createCombatString(RoundResult result) { - return ""; + private enum Element { + NORMAL, + FIRE, + WATER; + private Element[] strong; + private Element[] weak; + + // improvement: map to get mods straight from this enum + + static { + NORMAL.strong = new Element[]{WATER}; + NORMAL.weak = new Element[]{FIRE}; + + FIRE.strong = new Element[]{NORMAL}; + FIRE.weak = new Element[]{WATER}; + + WATER.strong = new Element[]{FIRE}; + WATER.weak = new Element[]{NORMAL}; + } + } + + private Pair getElementMod(Card left, Card right) { + Pair returnMods = new Pair<>(ElementMod.NONE, ElementMod.NONE); + + if (!left.name().endsWith("Spell") && !right.name().endsWith("Spell")) return returnMods; + + Element leftElement = Element.NORMAL; + Element rightElement = Element.NORMAL; + + for (val value : Element.values()) { + if (left.name().toLowerCase().startsWith(value.name().toLowerCase())) leftElement = value; + if (right.name().toLowerCase().startsWith(value.name().toLowerCase())) rightElement = value; + } + + final Element finalLeftElement = leftElement; // lambdas + final Element finalRightElement = rightElement; + + if (Arrays.stream(leftElement.strong).anyMatch(value -> value == finalRightElement)) returnMods.setLeft(ElementMod.DOUBLE); + else if (Arrays.stream(leftElement.weak).anyMatch(value -> value == finalRightElement)) returnMods.setLeft(ElementMod.HALF); + + if (Arrays.stream(rightElement.strong).anyMatch(value -> value == finalLeftElement)) returnMods.setRight(ElementMod.DOUBLE); + else if (Arrays.stream(rightElement.weak).anyMatch(value -> value == finalLeftElement)) returnMods.setRight(ElementMod.HALF); + + return returnMods; + } + + private RoundResult fight(FightDTO left, FightDTO right) { + if (this.isImmune(left.card(), right.card())) return new RoundResult(left, right, false, ElementMod.NONE, ElementMod.NONE); + if (this.isImmune(right.card(), left.card())) return new RoundResult(right, left, false, ElementMod.NONE, ElementMod.NONE); + + Pair dmgMods = getElementMod(left.card(), right.card()); + + boolean leftWins = left.card().damage()*dmgMods.left().percentMod > right.card().damage()*dmgMods.right().percentMod; + return new RoundResult( + leftWins ? left : right, + leftWins ? right : left, + left.card().damage()*dmgMods.left().percentMod == right.card().damage()*dmgMods.right().percentMod, + leftWins ? dmgMods.left() : dmgMods.right(), + leftWins ? dmgMods.right() : dmgMods.left()); + } + + private String createCombatString(int round, RoundResult result) { + StringBuilder stringBuilder = new StringBuilder(); + stringBuilder + .append(round) + .append(": ") + .append(String.format("%s: %s (%s damage)", + result.winner().player().name, + result.winner().card().name(), + result.winner().card().damage())) + .append(" vs. ") + .append(String.format("%s: %s (%s damage)", + result.loser().player().name, + result.loser().card().name(), + result.loser().card().damage())) + .append(" => "); + + if (result.winnerMod() != ElementMod.NONE || result.loserMod() != ElementMod.NONE) { + stringBuilder + .append(String.format("%s vs. %s", + result.winner().card().damage(), + result.loser().card().damage())) + .append(" -> ") + .append(String.format("%s vs. %s", + result.winner().card().damage() * result.winnerMod().percentMod, + result.loser().card().damage() * result.loserMod().percentMod)) + .append(" => "); + } + + if (result.draw()) { + return stringBuilder.append("Draw").toString(); + } + + stringBuilder + .append(result.winner().card().name()) + .append(" wins"); + + return stringBuilder.toString(); } } diff --git a/src/main/java/at/nanopenguin/mtcg/application/Combatant.java b/src/main/java/at/nanopenguin/mtcg/application/Combatant.java index 5b397d8..ec9654a 100644 --- a/src/main/java/at/nanopenguin/mtcg/application/Combatant.java +++ b/src/main/java/at/nanopenguin/mtcg/application/Combatant.java @@ -47,7 +47,7 @@ public class Combatant { .executeUpdate(); }; - public Card getCard() { + public Card getAndRemoveCard() { return this.deck.popRandom(); }