From 97ef76bc5adb1be7dc517b904e42dd50551e4065 Mon Sep 17 00:00:00 2001 From: WRORacer Date: Fri, 2 Jun 2023 10:10:58 +0200 Subject: [PATCH] UNO-4 Add Game Logic --- .../java/de/wroracer/uno/engine/Game.java | 117 ++++++++++++++++++ .../{unoengine => uno/engine}/Player.java | 10 +- .../{unoengine => uno/engine}/card/Card.java | 2 +- .../{unoengine => uno/engine}/card/Deck.java | 2 +- .../engine}/card/DrawTwoCard.java | 6 +- .../engine}/card/ReverseCard.java | 6 +- .../engine}/card/SkipCard.java | 6 +- .../de/wroracer/uno/engine/card/Special.java | 9 ++ .../engine}/card/WildCard.java | 2 +- .../engine}/card/WildDrawFourCard.java | 6 +- .../engine/error/CardNotPlayableError.java | 9 ++ .../wroracer/uno/engine/error/UnoError.java | 16 +++ src/main/java/de/wroracer/unoengine/Game.java | 62 ---------- .../de/wroracer/unoengine/card/Special.java | 9 -- .../java/de/wroracer/uno/engine/GameTest.java | 70 +++++++++++ .../engine}/card/CardTest.java | 6 +- 16 files changed, 244 insertions(+), 94 deletions(-) create mode 100644 src/main/java/de/wroracer/uno/engine/Game.java rename src/main/java/de/wroracer/{unoengine => uno/engine}/Player.java (64%) rename src/main/java/de/wroracer/{unoengine => uno/engine}/card/Card.java (98%) rename src/main/java/de/wroracer/{unoengine => uno/engine}/card/Deck.java (98%) rename src/main/java/de/wroracer/{unoengine => uno/engine}/card/DrawTwoCard.java (61%) rename src/main/java/de/wroracer/{unoengine => uno/engine}/card/ReverseCard.java (61%) rename src/main/java/de/wroracer/{unoengine => uno/engine}/card/SkipCard.java (59%) create mode 100644 src/main/java/de/wroracer/uno/engine/card/Special.java rename src/main/java/de/wroracer/{unoengine => uno/engine}/card/WildCard.java (91%) rename src/main/java/de/wroracer/{unoengine => uno/engine}/card/WildDrawFourCard.java (62%) create mode 100644 src/main/java/de/wroracer/uno/engine/error/CardNotPlayableError.java create mode 100644 src/main/java/de/wroracer/uno/engine/error/UnoError.java delete mode 100644 src/main/java/de/wroracer/unoengine/Game.java delete mode 100644 src/main/java/de/wroracer/unoengine/card/Special.java create mode 100644 src/test/java/de/wroracer/uno/engine/GameTest.java rename src/test/java/de/wroracer/{unoengine => uno/engine}/card/CardTest.java (84%) diff --git a/src/main/java/de/wroracer/uno/engine/Game.java b/src/main/java/de/wroracer/uno/engine/Game.java new file mode 100644 index 0000000..a0c72b4 --- /dev/null +++ b/src/main/java/de/wroracer/uno/engine/Game.java @@ -0,0 +1,117 @@ +package de.wroracer.uno.engine; + +import de.wroracer.uno.engine.card.Card; +import de.wroracer.uno.engine.card.Deck; +import de.wroracer.uno.engine.card.Special; +import de.wroracer.uno.engine.error.CardNotPlayableError; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class Game { + + private final Deck deck; + private final UUID id; + private final List players; + private final boolean clockwise = true; + private State state; + private Player currentTurn; + + public Game() { + deck = new Deck(); + players = new ArrayList<>(); + id = UUID.randomUUID(); + + System.out.println(deck); + } + + + public Player addPlayer() { + Player p = new Player(); + players.add(p); + return p; + } + + public void removePlayer(Player p) { + players.remove(p); + } + + public void startGame() { + this.state = State.IN_GAME; + for (int i = 0; i < players.size() * 7; i++) { + players.get(i % players.size()).getHand().add(deck.drawCard()); + } + deck.discard(deck.drawCard()); + this.currentTurn = players.get(0); + } + + public Card getCurrentCard() { + return deck.currentCard(); + } + + + public void play(Card card) { + if (card.canPlayedOn(deck.currentCard())) { + deck.discard(card); + currentTurn.getHand().remove(card); + if (card instanceof Special) { + ((Special) card).execute(this); + } + nextTurn(); + } else { + throw new CardNotPlayableError(card, deck.currentCard()); + } + } + + private void nextTurn() { + if (currentTurn.getHand().size() == 0) { + state = State.FINISHED; + return; + } + int index = players.indexOf(currentTurn); + if (clockwise) { + index++; + if (index >= players.size()) { + index = 0; + } + } else { + index--; + if (index < 0) { + index = players.size() - 1; + } + } + currentTurn = players.get(index); + } + + public boolean canBePlay(Card card) { + return card.canPlayedOn(deck.currentCard()); + } + + public void draw(Player player) { + if (player == currentTurn) { + player.getHand().add(deck.drawCard()); + nextTurn(); + } else { + player.getHand().add(deck.drawCard()); + } + } + + public UUID getId() { + return id; + } + + public Player getCurrentTurn() { + return currentTurn; + } + + public List getPlayers() { + return players; + } + + public enum State { + LOBBY, + IN_GAME, + FINISHED + } +} diff --git a/src/main/java/de/wroracer/unoengine/Player.java b/src/main/java/de/wroracer/uno/engine/Player.java similarity index 64% rename from src/main/java/de/wroracer/unoengine/Player.java rename to src/main/java/de/wroracer/uno/engine/Player.java index 13c11a0..775e780 100644 --- a/src/main/java/de/wroracer/unoengine/Player.java +++ b/src/main/java/de/wroracer/uno/engine/Player.java @@ -1,16 +1,16 @@ -package de.wroracer.unoengine; +package de.wroracer.uno.engine; -import de.wroracer.unoengine.card.Card; +import de.wroracer.uno.engine.card.Card; import java.util.ArrayList; import java.util.List; import java.util.UUID; public class Player { - private List hand; - private UUID id; + private final List hand; + private final UUID id; - public Player(){ + public Player() { id = UUID.randomUUID(); hand = new ArrayList<>(); } diff --git a/src/main/java/de/wroracer/unoengine/card/Card.java b/src/main/java/de/wroracer/uno/engine/card/Card.java similarity index 98% rename from src/main/java/de/wroracer/unoengine/card/Card.java rename to src/main/java/de/wroracer/uno/engine/card/Card.java index 3d16df0..19a63e2 100644 --- a/src/main/java/de/wroracer/unoengine/card/Card.java +++ b/src/main/java/de/wroracer/uno/engine/card/Card.java @@ -1,4 +1,4 @@ -package de.wroracer.unoengine.card; +package de.wroracer.uno.engine.card; public class Card { protected Color color; diff --git a/src/main/java/de/wroracer/unoengine/card/Deck.java b/src/main/java/de/wroracer/uno/engine/card/Deck.java similarity index 98% rename from src/main/java/de/wroracer/unoengine/card/Deck.java rename to src/main/java/de/wroracer/uno/engine/card/Deck.java index e5a7560..891651e 100644 --- a/src/main/java/de/wroracer/unoengine/card/Deck.java +++ b/src/main/java/de/wroracer/uno/engine/card/Deck.java @@ -1,4 +1,4 @@ -package de.wroracer.unoengine.card; +package de.wroracer.uno.engine.card; import java.util.ArrayDeque; import java.util.List; diff --git a/src/main/java/de/wroracer/unoengine/card/DrawTwoCard.java b/src/main/java/de/wroracer/uno/engine/card/DrawTwoCard.java similarity index 61% rename from src/main/java/de/wroracer/unoengine/card/DrawTwoCard.java rename to src/main/java/de/wroracer/uno/engine/card/DrawTwoCard.java index 0dfb7ec..ff6ec84 100644 --- a/src/main/java/de/wroracer/unoengine/card/DrawTwoCard.java +++ b/src/main/java/de/wroracer/uno/engine/card/DrawTwoCard.java @@ -1,6 +1,6 @@ -package de.wroracer.unoengine.card; +package de.wroracer.uno.engine.card; -import de.wroracer.unoengine.Game; +import de.wroracer.uno.engine.Game; public class DrawTwoCard extends Card implements Special { public DrawTwoCard(Color color) { @@ -8,7 +8,7 @@ public DrawTwoCard(Color color) { } @Override - public void performAction(Game game) { + public void execute(Game game) { //TODO } } diff --git a/src/main/java/de/wroracer/unoengine/card/ReverseCard.java b/src/main/java/de/wroracer/uno/engine/card/ReverseCard.java similarity index 61% rename from src/main/java/de/wroracer/unoengine/card/ReverseCard.java rename to src/main/java/de/wroracer/uno/engine/card/ReverseCard.java index 00e6296..c09118e 100644 --- a/src/main/java/de/wroracer/unoengine/card/ReverseCard.java +++ b/src/main/java/de/wroracer/uno/engine/card/ReverseCard.java @@ -1,6 +1,6 @@ -package de.wroracer.unoengine.card; +package de.wroracer.uno.engine.card; -import de.wroracer.unoengine.Game; +import de.wroracer.uno.engine.Game; public class ReverseCard extends Card implements Special { public ReverseCard(Color color) { @@ -8,7 +8,7 @@ public ReverseCard(Color color) { } @Override - public void performAction(Game game) { + public void execute(Game game) { //TODO } } diff --git a/src/main/java/de/wroracer/unoengine/card/SkipCard.java b/src/main/java/de/wroracer/uno/engine/card/SkipCard.java similarity index 59% rename from src/main/java/de/wroracer/unoengine/card/SkipCard.java rename to src/main/java/de/wroracer/uno/engine/card/SkipCard.java index 1e836a2..330534d 100644 --- a/src/main/java/de/wroracer/unoengine/card/SkipCard.java +++ b/src/main/java/de/wroracer/uno/engine/card/SkipCard.java @@ -1,6 +1,6 @@ -package de.wroracer.unoengine.card; +package de.wroracer.uno.engine.card; -import de.wroracer.unoengine.Game; +import de.wroracer.uno.engine.Game; public class SkipCard extends Card implements Special { public SkipCard(Color color) { @@ -8,7 +8,7 @@ public SkipCard(Color color) { } @Override - public void performAction(Game game) { + public void execute(Game game) { //TODO } } diff --git a/src/main/java/de/wroracer/uno/engine/card/Special.java b/src/main/java/de/wroracer/uno/engine/card/Special.java new file mode 100644 index 0000000..76c93bf --- /dev/null +++ b/src/main/java/de/wroracer/uno/engine/card/Special.java @@ -0,0 +1,9 @@ +package de.wroracer.uno.engine.card; + +import de.wroracer.uno.engine.Game; + +public interface Special { + + void execute(Game game); + +} diff --git a/src/main/java/de/wroracer/unoengine/card/WildCard.java b/src/main/java/de/wroracer/uno/engine/card/WildCard.java similarity index 91% rename from src/main/java/de/wroracer/unoengine/card/WildCard.java rename to src/main/java/de/wroracer/uno/engine/card/WildCard.java index 1582b9a..9277153 100644 --- a/src/main/java/de/wroracer/unoengine/card/WildCard.java +++ b/src/main/java/de/wroracer/uno/engine/card/WildCard.java @@ -1,4 +1,4 @@ -package de.wroracer.unoengine.card; +package de.wroracer.uno.engine.card; public class WildCard extends Card { public WildCard() { diff --git a/src/main/java/de/wroracer/unoengine/card/WildDrawFourCard.java b/src/main/java/de/wroracer/uno/engine/card/WildDrawFourCard.java similarity index 62% rename from src/main/java/de/wroracer/unoengine/card/WildDrawFourCard.java rename to src/main/java/de/wroracer/uno/engine/card/WildDrawFourCard.java index 6b2efd9..6760e42 100644 --- a/src/main/java/de/wroracer/unoengine/card/WildDrawFourCard.java +++ b/src/main/java/de/wroracer/uno/engine/card/WildDrawFourCard.java @@ -1,6 +1,6 @@ -package de.wroracer.unoengine.card; +package de.wroracer.uno.engine.card; -import de.wroracer.unoengine.Game; +import de.wroracer.uno.engine.Game; public class WildDrawFourCard extends WildCard implements Special { public WildDrawFourCard() { @@ -8,7 +8,7 @@ public WildDrawFourCard() { } @Override - public void performAction(Game game) { + public void execute(Game game) { //TODO } } diff --git a/src/main/java/de/wroracer/uno/engine/error/CardNotPlayableError.java b/src/main/java/de/wroracer/uno/engine/error/CardNotPlayableError.java new file mode 100644 index 0000000..4a02cdc --- /dev/null +++ b/src/main/java/de/wroracer/uno/engine/error/CardNotPlayableError.java @@ -0,0 +1,9 @@ +package de.wroracer.uno.engine.error; + +import de.wroracer.uno.engine.card.Card; + +public class CardNotPlayableError extends UnoError { + public CardNotPlayableError(Card play, Card current) { + super("The card " + play + " is not playable on " + current); + } +} diff --git a/src/main/java/de/wroracer/uno/engine/error/UnoError.java b/src/main/java/de/wroracer/uno/engine/error/UnoError.java new file mode 100644 index 0000000..59d47a5 --- /dev/null +++ b/src/main/java/de/wroracer/uno/engine/error/UnoError.java @@ -0,0 +1,16 @@ +package de.wroracer.uno.engine.error; + +public class UnoError extends Error { + public UnoError(String message) { + super(message); + } + + public UnoError(String message, Throwable cause) { + super(message, cause); + } + + public UnoError(Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/de/wroracer/unoengine/Game.java b/src/main/java/de/wroracer/unoengine/Game.java deleted file mode 100644 index 92ec31d..0000000 --- a/src/main/java/de/wroracer/unoengine/Game.java +++ /dev/null @@ -1,62 +0,0 @@ -package de.wroracer.unoengine; - -import de.wroracer.unoengine.card.Card; -import de.wroracer.unoengine.card.Deck; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - -public class Game { - - private State state; - private final Deck deck; - - private final UUID id; - private final List players; - private Player currentTurn; - - public Game() { - deck = new Deck(); - players = new ArrayList<>(); - id = UUID.randomUUID(); - - System.out.println(deck); - } - - public static void main(String[] args) { - new Game(); - } - - public Player addPlayer() { - Player p = new Player(); - players.add(p); - return p; - } - - public void removePlayer(Player p) { - players.remove(p); - } - - public void startGame() { - this.state = State.IN_GAME; - for (int i = 0; i < players.size() * 7; i++) { - players.get(i % players.size()).getHand().add(deck.drawCard()); - } - deck.discard(deck.drawCard()); - } - - public Card getCurrentCard() { - return deck.currentCard(); - } - - public UUID getId() { - return id; - } - - public enum State { - LOBBY, - IN_GAME, - FINISHED - } -} diff --git a/src/main/java/de/wroracer/unoengine/card/Special.java b/src/main/java/de/wroracer/unoengine/card/Special.java deleted file mode 100644 index d15380f..0000000 --- a/src/main/java/de/wroracer/unoengine/card/Special.java +++ /dev/null @@ -1,9 +0,0 @@ -package de.wroracer.unoengine.card; - -import de.wroracer.unoengine.Game; - -public interface Special { - - void performAction(Game game); - -} diff --git a/src/test/java/de/wroracer/uno/engine/GameTest.java b/src/test/java/de/wroracer/uno/engine/GameTest.java new file mode 100644 index 0000000..2d1f790 --- /dev/null +++ b/src/test/java/de/wroracer/uno/engine/GameTest.java @@ -0,0 +1,70 @@ +package de.wroracer.uno.engine; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +class GameTest { + + private Game game; + + @Test + void addPlayer() { + Player p = game.addPlayer(); + assertEquals(1, game.getPlayers().size()); + assertEquals(p, game.getPlayers().get(0)); + + Player p2 = game.addPlayer(); + assertEquals(2, game.getPlayers().size()); + assertEquals(p2, game.getPlayers().get(1)); + } + + @Test + void removePlayer() { + Player p = game.addPlayer(); + assertEquals(1, game.getPlayers().size()); + assertEquals(p, game.getPlayers().get(0)); + + game.removePlayer(p); + assertEquals(0, game.getPlayers().size()); + + Player p2 = game.addPlayer(); + assertEquals(1, game.getPlayers().size()); + assertEquals(p2, game.getPlayers().get(0)); + + Player p3 = game.addPlayer(); + assertEquals(2, game.getPlayers().size()); + assertEquals(p3, game.getPlayers().get(1)); + + game.removePlayer(p2); + + assertEquals(1, game.getPlayers().size()); + assertEquals(p3, game.getPlayers().get(0)); + } + + @Test + void startGame() { + Player p1 = game.addPlayer(); + Player p2 = game.addPlayer(); + Player p3 = game.addPlayer(); + Player p4 = game.addPlayer(); + + game.startGame(); + + assertEquals(7, p1.getHand().size()); + assertEquals(7, p2.getHand().size()); + assertEquals(7, p3.getHand().size()); + assertEquals(7, p4.getHand().size()); + + assertEquals(4, game.getPlayers().size()); + assertNotNull(game.getCurrentCard()); + + } + + @BeforeEach + void setUp() { + game = new Game(); + } +} \ No newline at end of file diff --git a/src/test/java/de/wroracer/unoengine/card/CardTest.java b/src/test/java/de/wroracer/uno/engine/card/CardTest.java similarity index 84% rename from src/test/java/de/wroracer/unoengine/card/CardTest.java rename to src/test/java/de/wroracer/uno/engine/card/CardTest.java index 8f0aaca..056e2f7 100644 --- a/src/test/java/de/wroracer/unoengine/card/CardTest.java +++ b/src/test/java/de/wroracer/uno/engine/card/CardTest.java @@ -1,9 +1,9 @@ -package de.wroracer.unoengine.card; +package de.wroracer.uno.engine.card; import org.junit.jupiter.api.Test; -import static de.wroracer.unoengine.card.Card.Color.*; -import static de.wroracer.unoengine.card.Card.Type.*; +import static de.wroracer.uno.engine.card.Card.Color.*; +import static de.wroracer.uno.engine.card.Card.Type.*; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue;