diff --git a/card-game/build.gradle b/card-game/build.gradle deleted file mode 100644 index a85e5c54..00000000 --- a/card-game/build.gradle +++ /dev/null @@ -1,123 +0,0 @@ -plugins { - id "java" - id "org.openjfx.javafxplugin" version "0.0.13" - id "com.github.johnrengelman.shadow" version "7.0.0" -} - -configurations { - internal - implementation.extendsFrom(internal) -} - -// JavaFX dependencies -javafx { - version = "20" - modules = ["javafx.controls", "javafx.graphics", "javafx.fxml", "javafx.media"] -} - -// Project dependencies -dependencies { - - // https://mvnrepository.com/artifact/org.jetbrains/annotations - implementation "org.jetbrains:annotations:24.0.1" - - // JFxFramework - implementation project(":framework") - - // https://mvnrepository.com/artifact/com.google.dagger/dagger - implementation group: "com.google.dagger", name: "dagger", version: "2.42" - - // https://mvnrepository.com/artifact/com.google.dagger/dagger-compiler - annotationProcessor group: "com.google.dagger", name: "dagger-compiler", version: "2.42" - - // https://mvnrepository.com/artifacts/fr.brouillard.oss/cssfx - implementation group: "fr.brouillard.oss", name: "cssfx", version: "11.5.1" - - // https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit - implementation group: "com.squareup.retrofit2", name: "retrofit", version: "2.9.0" - - // https://mvnrepository.com/artifact/com.squareup.retrofit2/adapter-rxjava3 - implementation group: "com.squareup.retrofit2", name: "adapter-rxjava3", version: "2.9.0" - - // https://mvnrepository.com/artifact/com.squareup.retrofit2/converter-jackson - implementation group: "com.squareup.retrofit2", name: "converter-jackson", version: "2.9.0" - - // https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core - implementation group: "com.fasterxml.jackson.core", name: "jackson-core", version: "2.13.3" - - // https://mvnrepository.com/artifact/io.reactivex.rxjava3/rxjava - implementation group: "io.reactivex.rxjava3", name: "rxjava", version: "3.1.4" - - // https://mvnrepository.com/artifact/org.glassfish.tyrus.bundles/tyrus-standalone-client/1.9 - implementation group: "org.glassfish.tyrus.bundles", name: "tyrus-standalone-client", version: "1.9" - - // https://mvnrepository.com/artifact/javax.websocket/javax.websocket-api/1.1 - compileOnly group: "javax.websocket", name: "javax.websocket-api", version: "1.1" - - // https://mvnrepository.com/artifact/org.glassfish.tyrus/tyrus-client/1.15 - implementation group: "org.glassfish.tyrus", name: "tyrus-client", version: "1.15" - - // https://mvnrepository.com/artifact/org.glassfish.tyrus/tyrus-container-grizzly-client/1.15 - implementation group: "org.glassfish.tyrus", name: "tyrus-container-grizzly-client", version: "1.15" - - annotationProcessor project(':annotation-processor') -} - -java { - sourceCompatibility = getVersionForMajor(javaSourceVersion) - targetCompatibility = getVersionForMajor(javaTargetVersion) - - if (generateSourcesJar) { - withSourcesJar() - } - if (generateJavadocJar) { - withJavadocJar() - } -} - -sourcesJar { - duplicatesStrategy = DuplicatesStrategy.INCLUDE -} - -jar { - from { - configurations.internal.collect { it.isDirectory() ? it : zipTree(it) } - } - - manifest { - attributes( - "Manifest-Version": 1.0, - "Class-Path": ".", - "Main-Class": "io.github.sekassel.person.Main" - ) - } - - duplicatesStrategy = DuplicatesStrategy.EXCLUDE -} - -compileJava { - options.encoding = "UTF-8" - options.sourcepath = sourceSets.main.resources.getSourceDirectories() -} -javadoc { options.encoding = "UTF-8" } - -repositories { - mavenCentral() - maven { - name = "jitpack" - url = "https://jitpack.io" - } -} - -group projectGroup -version projectVersion - -// Include local jar dependencies -dependencies { - implementation fileTree(dir: "libs/implementation", include: "*.jar") - internal fileTree(dir: "libs/internal", include: "*.jar") -} - -static JavaVersion getVersionForMajor(String version) { - return JavaVersion.values().find { (it.majorVersion == version) } -} diff --git a/card-game/libs/implementation/.gitkeep b/card-game/libs/implementation/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/card-game/libs/internal/.gitkeep b/card-game/libs/internal/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/card-game/src/main/java/io/github/sekassel/uno/App.java b/card-game/src/main/java/io/github/sekassel/uno/App.java deleted file mode 100644 index 74036b70..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/App.java +++ /dev/null @@ -1,93 +0,0 @@ -package io.github.sekassel.uno; - -import io.github.sekassel.uno.dagger.DaggerMainComponent; -import io.github.sekassel.uno.dagger.MainComponent; -import javafx.stage.Stage; -import org.fulib.fx.FulibFxApp; - -import java.nio.file.Path; -import java.util.Map; -import java.util.logging.Level; - -import static javafx.scene.input.KeyEvent.KEY_PRESSED; - -/** - * The main class of your application. - */ -public class App extends FulibFxApp { - - - /** - * The dagger component of the application. - */ - private final MainComponent component; - - /** - * The constructor of the application. - */ - public App() { - super(); - - // Create a new dagger component as a starting point for the dependency injection - this.component = DaggerMainComponent.builder().mainApp(this).build(); - } - - /** - * The start method of the application. - * This method is called by the {@link Main} class when the application is started. - * - * @param primaryStage The primary stage of the application - */ - @Override - public void start(Stage primaryStage) { - try { - - // Starting the framework, initializes all the necessary components - super.start(primaryStage); - - // Registering the routes of the application. See UnoRouting.java for more information. - registerRoutes(component.routes()); - - // Setting the default resource bundle of the application to the resource bundle provided by the component - setDefaultResourceBundle(component.bundle()); - - stage().addEventHandler(KEY_PRESSED, event -> { - if (event.getCode().toString().equals("F5")) { - this.refresh(); - } - }); - - this.setTitlePattern("Uno - %s"); - - // Setting the resource path to the resources folder of the project (required for reloading in dev) - // If the resource path is not set, the framework will use the default resource path (src/main/resources) - setResourcesPath(Path.of("card-game/src/main/resources/")); - - // Setting the path which the auto refresher should watch (required for auto-reloading in dev) - autoRefresher().setup(Path.of("card-game/src/main/resources/io/github/sekassel/uno")); - show("", Map.of()); - - } catch (Exception e) { - // If an error occurs while starting the application, we want to log it and exit the application - LOGGER.log(Level.SEVERE, "An error occurred while starting the application: " + e.getMessage(), e); - } - } - - /** - * The stop method of the application. This method will be called when the application stops, for example if the - * window is closed. - */ - @Override - public void stop() { - super.stop(); - } - - /** - * Returns the dagger component of the application. - * - * @return The dagger component - */ - public MainComponent component() { - return component; - } -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/Constants.java b/card-game/src/main/java/io/github/sekassel/uno/Constants.java deleted file mode 100644 index ff6a35e0..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/Constants.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.github.sekassel.uno; - -import javafx.scene.media.Media; - - -public class Constants { - - public static final int START_CARD_AMOUNT = 4; - - public static final int MAX_NAME_LENGTH = 16; - public static final String BOT_NAME = "Bot %s"; - - public static final int BOT_PLAY_DELAY = 2000; - - public static final String CARD_FONT_FAMILY = "System"; - public static final String BOT_ICON_FONT_FAMILY = "Cooper Black"; - public static final int CARD_FONT_SIZE = 64; - - public static final String CARD_STYLE = "-fx-border-radius: 10px; -fx-border-color: BLACK; -fx-border-width: 10px; -fx-background-color: %s; -fx-background-radius: 16px; -fx-background-insets: 3px;"; - - public static final Media SOUND_CLICK = new Media(Main.class.getResource("sound/click.mp3").toString()); - public static final Media SOUND_FAIL = new Media(Main.class.getResource("sound/fail.mp3").toString()); - - public static final String COUNTER_CLOCKWISE_ICON = "\u21BA"; - public static final String CLOCKWISE_ICON = "\u21BB"; - public static final String WILD_ICON = "\u2605"; - public static final String SKIP_ICON = "\u2A02"; - public static final String DRAW_TWO_ICON = "+2"; -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/Main.java b/card-game/src/main/java/io/github/sekassel/uno/Main.java deleted file mode 100644 index eb61be91..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/Main.java +++ /dev/null @@ -1,10 +0,0 @@ -package io.github.sekassel.uno; - -import javafx.application.Application; - -public class Main { - - public static void main(String[] args) { - Application.launch(App.class, args); - } -} \ No newline at end of file diff --git a/card-game/src/main/java/io/github/sekassel/uno/UnoRouting.java b/card-game/src/main/java/io/github/sekassel/uno/UnoRouting.java deleted file mode 100644 index dae0271a..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/UnoRouting.java +++ /dev/null @@ -1,40 +0,0 @@ -package io.github.sekassel.uno; - -import org.fulib.fx.annotation.Route; -import io.github.sekassel.uno.controller.*; - -import javax.inject.Inject; -import javax.inject.Provider; -import javax.inject.Singleton; - -/** - * This class is used to set up the routing for the application. - * Every route is mapped to a controller, which is then used to display the corresponding view. - *

- * The {@link Route} annotation is used to mark a controller as a route. - * The value of the annotation is the path of the route. - *

- * The controllers will be created using Providers, which in this case are injected by dagger. Therefore, the controllers - * need an empty constructor annotated with {@link Inject}. - */ -@Singleton -public class UnoRouting { - - @Inject - @Route("") - // The empty route is the default route. It is often used as the starting point of the application. - public Provider setupController; - - @Inject - @Route("ingame") - public Provider ingameController; - - @Inject - @Route("gameover") - public Provider gameOverController; - - @Inject - public UnoRouting() { - } - -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/controller/BotController.java b/card-game/src/main/java/io/github/sekassel/uno/controller/BotController.java deleted file mode 100644 index 1367e080..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/controller/BotController.java +++ /dev/null @@ -1,117 +0,0 @@ -package io.github.sekassel.uno.controller; - -import org.fulib.fx.annotation.controller.Component; -import org.fulib.fx.annotation.event.onDestroy; -import org.fulib.fx.annotation.event.onInit; -import org.fulib.fx.annotation.event.onRender; -import org.fulib.fx.annotation.param.Param; -import org.fulib.fx.controller.Subscriber; -import io.github.sekassel.uno.Constants; -import io.github.sekassel.uno.model.Player; -import io.github.sekassel.uno.service.GameService; -import javafx.fxml.FXML; -import javafx.scene.control.Label; -import javafx.scene.layout.VBox; -import javafx.scene.text.Font; - -import javax.inject.Inject; - -@Component(view = "sub/Bot.fxml") -public class BotController extends VBox { - - @FXML - public VBox botBox; - @FXML - public Label nameLabel; - @FXML - public Label currentCardsValueLabel; - @FXML - public Label iconLabel; - - @Inject - GameService gameService; - @Inject - Subscriber subscriber; - - @Param("bot") - private Player bot; - - @Param("parent") - private IngameController parent; - - @onInit - public void initSout() { - System.out.println(this + " initialized."); - } - - @onRender() - public void renderSout() { - System.out.println(this + " rendered."); - } - - @onDestroy - public void destroySout() { - System.out.println(this + " destroyed."); - } - - @onRender() - public void render() { - - botBox.setId(bot.getName().replace(" ", "")); - - updateCards(); - updateName(); - setupPropertyChangeListeners(); - } - - /** - * Sets up all the required listeners for displaying the card. - */ - private void setupPropertyChangeListeners() { - // Update the card amount if the cards of the bot change (or display a winning screen if the bot won the game) - this.subscriber.listen(bot.listeners(), Player.PROPERTY_CARDS, event -> { - updateCards(); - if (bot.getGame() != null && this.bot.getCards().isEmpty()) { - parent.displayWinner(this.bot); - } - }); - } - - /** - * Updates the card amount to the correct number. - */ - public void updateCards() { - currentCardsValueLabel.setText(String.valueOf(bot.getCards().size())); - } - - /** - * Updates the name to the correct value. - */ - public void updateName() { - this.nameLabel.setText(bot.getName()); - } - - /** - * Highlights a bot or removes the highlight from a bot. - * - * @param highlight Whether the bot should be highlighted - */ - public void highlight(boolean highlight) { - nameLabel.setUnderline(highlight); - iconLabel.setFont(Font.font(Constants.BOT_ICON_FONT_FAMILY, highlight ? 72 : 64)); - } - - @onDestroy - public void destroy() { - // Remove the bot from the game - this.gameService.getBotService().removeBot(bot); - this.subscriber.dispose(); - } - - @Inject - public BotController() { - super(); - System.out.println(this + " created."); - } - -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/controller/ButtonController.java b/card-game/src/main/java/io/github/sekassel/uno/controller/ButtonController.java deleted file mode 100644 index 34160453..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/controller/ButtonController.java +++ /dev/null @@ -1,52 +0,0 @@ -package io.github.sekassel.uno.controller; - -import org.fulib.fx.annotation.controller.Component; -import org.fulib.fx.annotation.event.onDestroy; -import org.fulib.fx.annotation.event.onInit; -import org.fulib.fx.annotation.event.onRender; -import javafx.event.ActionEvent; -import javafx.fxml.FXML; -import javafx.scene.layout.HBox; - -import javax.inject.Inject; - -@Component(view = "sub/Buttons.fxml") -public class ButtonController extends HBox { - - public void setParentController(IngameController parentController) { - this.parentController = parentController; - } - - private IngameController parentController; - - @Inject - public ButtonController() { - System.out.println(this + " created."); - } - - - @onInit - public void initSout() { - System.out.println(this + " initialized."); - } - - @onRender() - public void renderSout() { - System.out.println(this + " rendered."); - } - - @onDestroy - public void destroySout() { - System.out.println(this + " destroyed."); - } - - /** - * The method triggered by the wild card buttons. - * Different behaviour is defined by the id of the clicked button. - * Chooses the card color and plays the wild card as a colored card. - */ - @FXML - public void onWildPressed(ActionEvent event) { - this.parentController.onWildPressed(event); - } -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/controller/CardController.java b/card-game/src/main/java/io/github/sekassel/uno/controller/CardController.java deleted file mode 100644 index 291a46d6..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/controller/CardController.java +++ /dev/null @@ -1,124 +0,0 @@ -package io.github.sekassel.uno.controller; - -import org.fulib.fx.annotation.controller.Component; -import org.fulib.fx.annotation.event.onDestroy; -import org.fulib.fx.annotation.event.onInit; -import org.fulib.fx.annotation.event.onRender; -import org.fulib.fx.controller.Subscriber; -import io.github.sekassel.uno.Constants; -import io.github.sekassel.uno.model.Card; -import io.github.sekassel.uno.model.Player; -import io.github.sekassel.uno.service.GameService; -import io.github.sekassel.uno.util.Utils; -import javafx.fxml.FXML; -import javafx.scene.control.Label; -import javafx.scene.layout.VBox; -import javafx.scene.text.Font; -import javafx.scene.text.FontWeight; - -import javax.inject.Inject; - -@Component(view = "sub/Card.fxml") -public class CardController extends VBox { - - @FXML - public VBox cardScreen; - @FXML - public Label cardTypeLabel; - - @Inject - GameService gameService; - - @Inject - Subscriber subscriber; - - private Card card; - - @Inject - public CardController() { - System.out.println(this + " created."); - } - - @onRender - public void render() { - - cardScreen.setId((this.card.getColor() + "_" + this.card.getType()).toLowerCase()); - - setupPropertyChangeListeners(); - setupSelection(); - setColor(); - } - - /** - * Sets up all the required listeners for displaying the card. - */ - private void setupPropertyChangeListeners() { - // Change the card color if the card color changes (wild cards) - subscriber.listen(card.listeners(), Card.PROPERTY_COLOR, event -> setColor()); - } - - /** - * Set up a click listener so that the card will be selected when it's clicked. - */ - private void setupSelection() { - - Player owner = card.getOwner(); - - if (owner == null) { - return; - } - - cardScreen.setOnMouseClicked(event -> gameService.selectCard(this.card)); - } - - /** - * Update the color of the controller. - */ - private void setColor() { - cardScreen.setStyle(Utils.getCardStyle(this.card.getColor())); - cardTypeLabel.setText(card.getType().getIcon()); - } - - /** - * Highlights a card or removes the highlight from a card. - * - * @param highlight Whether the card should be highlighted - */ - public void highlight(boolean highlight) { - cardTypeLabel.setFont(Font.font(Constants.CARD_FONT_FAMILY, highlight ? FontWeight.BOLD : FontWeight.NORMAL, Constants.CARD_FONT_SIZE)); - cardTypeLabel.setUnderline(highlight); - } - - /** - * Sets the card that should be displayed. - * - * @param card The card that should be displayed - */ - public CardController setCard(Card card) { - this.card = card; - return this; - } - - @onDestroy - public void destroy() { - // Remove the card from the game - this.subscriber.dispose(); - } - - - @onInit - public void initSout() { - System.out.println(this + " initialized."); - } - - @onRender() - public void renderSout() { - System.out.println(this + " rendered."); - } - - @onDestroy - public void destroySout() { - System.out.println(this + " destroyed."); - } - -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/controller/GameOverController.java b/card-game/src/main/java/io/github/sekassel/uno/controller/GameOverController.java deleted file mode 100644 index 06ab881b..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/controller/GameOverController.java +++ /dev/null @@ -1,71 +0,0 @@ -package io.github.sekassel.uno.controller; - -import org.fulib.fx.annotation.controller.Controller; -import org.fulib.fx.annotation.controller.Title; -import org.fulib.fx.annotation.event.onDestroy; -import org.fulib.fx.annotation.event.onInit; -import org.fulib.fx.annotation.event.onRender; -import org.fulib.fx.annotation.param.Param; -import io.github.sekassel.uno.App; -import io.github.sekassel.uno.model.Player; -import javafx.fxml.FXML; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.layout.VBox; - -import javax.inject.Inject; -import javax.inject.Singleton; - -@Singleton -@Controller -@Title("Game Over") -public class GameOverController { - - @Inject - App app; - - @FXML - public VBox gameOverScreen; - @FXML - public Button backToMenuButton; - @FXML - public Label wonLabel; - - @Inject - public GameOverController() { - System.out.println(this + " created."); - } - - // This method will be called when the controller is rendered. Since we don't have to save the winner in a field, - // we can just pass it as a parameter to the method. - @onRender - public void render(@Param(value = "winner") Player player) { - wonLabel.setText(wonLabel.getText().formatted(player.getName())); - } - - /** - * The method triggered by the quit button. - * Displays the setup screen again. - */ - @FXML - private void backToMenu() { - this.app.show("/"); - } - - - @onInit - public void initSout() { - System.out.println(this + " initialized."); - } - - @onRender() - public void renderSout() { - System.out.println(this + " rendered."); - } - - @onDestroy - public void destroySout() { - System.out.println(this + " destroyed."); - } - -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/controller/IngameController.java b/card-game/src/main/java/io/github/sekassel/uno/controller/IngameController.java deleted file mode 100644 index 51b78498..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/controller/IngameController.java +++ /dev/null @@ -1,432 +0,0 @@ -package io.github.sekassel.uno.controller; - -import io.github.sekassel.uno.App; -import io.github.sekassel.uno.Constants; -import io.github.sekassel.uno.model.Card; -import io.github.sekassel.uno.model.Game; -import io.github.sekassel.uno.model.Player; -import io.github.sekassel.uno.service.GameService; -import io.github.sekassel.uno.util.CardColor; -import io.github.sekassel.uno.util.Utils; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.event.ActionEvent; -import javafx.fxml.FXML; -import javafx.scene.Parent; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.input.KeyCode; -import javafx.scene.layout.HBox; -import javafx.scene.layout.Pane; -import javafx.scene.layout.VBox; -import org.fulib.fx.annotation.controller.Controller; -import org.fulib.fx.annotation.controller.Resource; -import org.fulib.fx.annotation.controller.SubComponent; -import org.fulib.fx.annotation.controller.Title; -import org.fulib.fx.annotation.event.onDestroy; -import org.fulib.fx.annotation.event.onInit; -import org.fulib.fx.annotation.event.onKey; -import org.fulib.fx.annotation.event.onRender; -import org.fulib.fx.annotation.param.Param; -import org.fulib.fx.constructs.forloop.FxFor; -import org.fulib.fx.controller.Subscriber; - -import javax.inject.Inject; -import javax.inject.Provider; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.ResourceBundle; - -/** - * The controller for the ingame screen. - * Displays the game and handles the user input. - *

- * The controller annotation is required for the framework to recognize this class as a controller. - * As there is no view specified, the framework will use the default file name which is located in the 'resources' folder - * and has a name based on the class name (IngameController.class --> Ingame.fxml). - */ -@Controller -@Title -public class IngameController { - - private final BooleanProperty wildCardSelectedProperty = new SimpleBooleanProperty(); - private final BooleanProperty playersTurn = new SimpleBooleanProperty(); - private final BooleanProperty cardSelected = new SimpleBooleanProperty(); - - HashMap cards = new HashMap<>(); - HashMap bots = new HashMap<>(); - - // We're using dagger for injecting our dependencies - @Inject - App app; - @Inject - Subscriber subscriber; - @Inject - FxFor fxFor; - @Inject - GameService gameService; - @Inject - Provider botControllerProvider; - @Inject - Provider cardControllerProvider; - - @Inject - @Resource - ResourceBundle resourceBundle; - - @Inject - @SubComponent - @FXML - // Fields annotated with @SubComponent will be initialized and rendered with the controller. - // They can be placed manually in code or using the FXML file. - ButtonController buttonController; - - @FXML - private VBox colorSelectorBox; - @FXML - private HBox mainBox1; - @FXML - private HBox mainBox2; - @FXML - private HBox cardListHBox; - @FXML - private Button drawButton; - @FXML - private Button playButton; - @FXML - private Label playersTurnText; - @FXML - private Label directionIconLabel; - - - private CardController currentCardController; - - @Param("game") // Fields annotated with @Param will be injected when the controller is initialized - private Game game; - - @Inject - public IngameController() { - System.out.println(this + " created."); - // The annotation @Inject is required for dagger to recognize this constructor as an injectable constructor - } - - @onInit - public void init() { - buttonController.setParentController(this); - - // Initialize the game - this.gameService.initialize(this.game); - - } - - // Since this method is annotated wth @onRender, it will be called when the controller is rendered - @onRender - public void render() { - // Setup gui elements - setupPropertyChangeListeners(); - renderBots(); - displayLastPlayed(this.game.getCurrentCard()); - - - // Render the cards of the player - subscriber.subscribe( - fxFor.of(this.cardListHBox, this.game.getFirstPlayer().getCards(), cardControllerProvider, (controller, card) -> { - controller.setCard(card); - this.cards.put(card, controller); - controller.subscriber.subscribe(() -> this.cards.remove(card)); - }).disposable() - ); - } - - /** - * Sets up all the required listeners for displaying the game. - */ - private void setupPropertyChangeListeners() { - - // Listener for displaying the direction of the game - subscriber.listen(game.listeners(), Game.PROPERTY_CLOCKWISE, event -> - this.directionIconLabel.setText(this.game.isClockwise() ? Constants.CLOCKWISE_ICON : Constants.COUNTER_CLOCKWISE_ICON) - ); - - // Listener for displaying the last played card in the center - subscriber.listen(game.listeners(), Game.PROPERTY_CURRENT_CARD, event -> { - Card newCard = (Card) event.getNewValue(); - if (newCard != null) { - displayLastPlayed(newCard); - } - }); - - // Listener for toggling the play/color picker buttons when a wild card is selected - subscriber.listen(game.getFirstPlayer().listeners(), Player.PROPERTY_CURRENT_CARD, event -> - this.wildCardSelectedProperty.set(event.getNewValue() != null && ((Card) event.getNewValue()).getColor() == CardColor.WILD) - ); - - // Listener for highlighting the selected card - subscriber.listen(game.getFirstPlayer().listeners(), Player.PROPERTY_CURRENT_CARD, event -> { - if (event.getOldValue() != null) { - Card oldCard = ((Card) event.getOldValue()); - getControllerByCard(oldCard).highlight(false); - } - - if (event.getNewValue() != null) { - Card newCard = ((Card) event.getNewValue()); - getControllerByCard(newCard).highlight(true); - cardSelected.set(newCard.canBeOnTopOf(game.getCurrentCard())); - } else { - cardSelected.set(false); - } - }); - - - // Listener for toggling the play/draw button when the player is at turn and selecting the playing bot - subscriber.listen(game.listeners(), Game.PROPERTY_CURRENT_PLAYER, event -> { - Player newPlayer = (Player) event.getNewValue(); - Player oldPlayer = (Player) event.getOldValue(); - - BotController oldController = getControllerByBot(oldPlayer); - BotController newController = getControllerByBot(newPlayer); - - // Highlight the next player (and remove the highlighting from the old one) - // As human players don't have a controller, the if-statement won't pass - if (oldController != null) { - oldController.highlight(false); - } - if (newController != null) { - newController.highlight(true); - } - - // If the new player is a human, it's the player's turn now - boolean isHuman = this.game.getFirstPlayer().equals(newPlayer); - playersTurn.set(isHuman); - - // If the new player is a bot, let the bot play - if (!isHuman) { - this.gameService.getBotService().startTurn(newPlayer); - } - - }); - - // Listener for displaying the winner if the player wins - this.game.getFirstPlayer().listeners().addPropertyChangeListener(Player.PROPERTY_CARDS, - event -> { - // Check if the player wins - if (game.getFirstPlayer().getCards().isEmpty()) { - displayWinner(game.getFirstPlayer()); - } - } - ); - - playersTurn.set(true); - // Display the color selection when a wildcard has been selected and it's the player's turn - subscriber.bind(colorSelectorBox.visibleProperty(), wildCardSelectedProperty.and(playersTurn)); - // Disable the play button if the player selected a wildcard, has no card selected or if it's not the player's turn - subscriber.bind(playButton.disableProperty(), wildCardSelectedProperty.or(playersTurn.not()).or(cardSelected.not())); - // Disable the draw button if it isn't the player's turn - subscriber.bind(drawButton.disableProperty(), playersTurn.not()); - // Display the text if it's the player's turn - subscriber.bind(playersTurnText.visibleProperty(), playersTurn); - } - - /** - * The method triggered by the quit button. - * Display the setup screen again (with the currently used values as initial values). - */ - @FXML - public void onQuitPressed() { - System.out.println("Quit"); - this.app.show("/", Map.of("initialBotAmount", this.game.getPlayers().size() - 1, "initialText", this.game.getFirstPlayer().getName())); - } - - /** - * The method triggered by the draw button. - * Checks if it's the player's turn and then draws a new card. - * If the card can be played, play it (if it's a wild card randomize the color). - */ - @FXML - public void onDrawPressed() { - if (playersTurn.get()) { - Card drawn = this.gameService.handoutCards(game.getPlayers().get(0), 1).get(0); - if (drawn.canBeOnTopOf(game.getCurrentCard())) { - playCard(drawn, drawn.getColor() == CardColor.WILD ? Utils.getRandomColor(this.gameService.getRandom()) : null); - } else { - this.gameService.selectNextPlayer(game, 1); - Utils.playSound(Constants.SOUND_FAIL); - } - } - } - - @onKey(code = KeyCode.ESCAPE) - public void onKeyPressed() { - onQuitPressed(); - } - - /** - * The method triggered by the play button. - * Checks if it's the player's turn and then plays the currently selected card. - */ - @FXML - public void onPlayPressed() { - Card selected = this.game.getFirstPlayer().getCurrentCard(); - if (playersTurn.get() && selected != null) { - playCard(selected, null); - } - } - - /** - * The method triggered by the wild card buttons. - * Different behaviour is defined by the id of the clicked button. - * Chooses the card color and plays the wild card as a colored card. - */ - public void onWildPressed(ActionEvent event) { - Card selected = this.game.getFirstPlayer().getCurrentCard(); - Button pressed = (Button) event.getSource(); - CardColor color = switch (pressed.getId()) { - case "redButton" -> CardColor.RED; - case "blueButton" -> CardColor.BLUE; - case "yellowButton" -> CardColor.YELLOW; - case "greenButton" -> CardColor.GREEN; - default -> null; - }; - playCard(selected, color); - } - - /** - * Plays a card and changes its color if set. - * - * @param card The card to play - * @param color The color the card should become (not set if null) - */ - private void playCard(Card card, CardColor color) { - this.gameService.playRound(card, color); - } - - /** - * Creates bot controllers and renders them at the correct place. - */ - private void renderBots() { - List players = this.game.getPlayers(); - players.forEach(player -> { - if (this.game.getFirstPlayer() == player) - return; - - // Create a new controller for the bot. Since the controller isn't rendered by the framework, we have to initialize it manually using initAndRender. - // Since the controller will persist for the whole lifetime of the game, we can let the framework handle the destruction of the controller. - BotController botController = app.initAndRender(botControllerProvider.get(), Map.of("bot", player, "parent", this), subscriber); - - bots.put(player, botController); - - switch (players.indexOf(player)) { - case 1 -> renderBot(botController, mainBox2, 0); - case 2 -> renderBot(botController, mainBox1, 0); - case 3 -> renderBot(botController, mainBox2, 1); - } - - }); - - } - - /** - * Renders a bot controller at a given pane and index. - * - * @param botNode The controller to be rendered - * @param pane Where the controller should be displayed - * @param index The index of the bot controller - */ - private void renderBot(Parent botNode, Pane pane, int index) { - System.out.println("Rendering bot " + botNode + " at " + pane + " with index " + index); - pane.getChildren().remove(index); - pane.getChildren().add(index, botNode); - } - - /** - * Displays a card as the last played card. - * - * @param card The card that has been played - */ - public void displayLastPlayed(Card card) { - - // Destroy the controller of the last played card - if (currentCardController != null) { - // We have to destroy the controller manually, since it was rendered manually (see below) - app.destroy(currentCardController); - } - - // Remove the last played card if it exists - if (mainBox2.getChildren().size() >= 3) { - mainBox2.getChildren().remove(1); - } - - // Create a new controller and initialize it, if there isn't already one - if (!cards.containsKey(card)) { - // Create a new controller for the card. Since the controller isn't rendered by the framework, we have to initialize it manually using initAndRender. - // Since the controller won't persist for the whole lifetime of the game, we have to handle the destruction of the controller manually (see above). - CardController controller = app.initAndRender(cardControllerProvider.get().setCard(card)); - cards.put(card, controller); - } - - // Move the controller in the middle - CardController newController = getControllerByCard(card); - - mainBox2.getChildren().add(1, newController); - - this.currentCardController = newController; - - } - - - /** - * Returns the controller for a given card. - * - * @param card The card of which the controller is searched - * @return The controller of the card or null - */ - public CardController getControllerByCard(Card card) { - return cards.get(card); - } - - /** - * Returns the controller for a given bot. - * - * @param bot The bot of which the controller is searched - * @return The controller of the bot or null - */ - public BotController getControllerByBot(Player bot) { - return bots.get(bot); - } - - /** - * Displays a winning screen with a given player as the winner of the game. - * - * @param player The player who won the game - */ - public void displayWinner(Player player) { - // In order to show the winner screen, we have to start with a '/', since otherwise path traversal would lead us - // to the controller at the route '/ingame/gameover', which isn't specified. - this.app.show("/gameover", Map.of("winner", player)); - } - - @onDestroy - public void destroy() { - // Remove the card from the game - this.subscriber.dispose(); - } - - - @onInit - public void initSout() { - System.out.println(this + " initialized."); - } - - @onRender() - public void renderSout() { - System.out.println(this + " rendered."); - } - - @onDestroy - public void destroySout() { - System.out.println(this + " destroyed."); - } - - -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/controller/SetupController.java b/card-game/src/main/java/io/github/sekassel/uno/controller/SetupController.java deleted file mode 100644 index eeedf0f7..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/controller/SetupController.java +++ /dev/null @@ -1,110 +0,0 @@ -package io.github.sekassel.uno.controller; - -import org.fulib.fx.annotation.controller.Controller; -import org.fulib.fx.annotation.controller.Title; -import org.fulib.fx.annotation.event.onDestroy; -import org.fulib.fx.annotation.event.onInit; -import org.fulib.fx.annotation.event.onRender; -import org.fulib.fx.annotation.param.Param; -import org.fulib.fx.controller.Subscriber; -import io.github.sekassel.uno.App; -import io.github.sekassel.uno.Constants; -import io.github.sekassel.uno.model.Game; -import io.github.sekassel.uno.service.GameService; -import io.github.sekassel.uno.util.Utils; -import javafx.fxml.FXML; -import javafx.scene.control.Button; -import javafx.scene.control.Slider; -import javafx.scene.control.TextField; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Map; - -@Controller -@Singleton -@Title("Setup") -public class SetupController { - - @FXML - public Slider botAmountSlider; - @FXML - public TextField nicknameField; - @FXML - public Button playButton; - - @Inject - GameService gameService; - @Inject - App app; - @Inject - Subscriber subscriber; - - @Param("initialText") - private String initialText; // The initial text that will be display in the name input - @Param("initialBotAmount") - private Integer initialBotAmount; // The initial bot amount that will be selected - - @Inject - public SetupController() { - } - - - @onRender - public void render() { - - // Display initial values if set - if (initialText != null) - nicknameField.setText(initialText); - - if (initialBotAmount != null) { - botAmountSlider.setValue(initialBotAmount); - } - - setupPlayButton(); - } - - /** - * Changes the play button to only be active if a name is present - */ - private void setupPlayButton() { - playButton.disableProperty().bind(nicknameField.textProperty().isEmpty()); - subscriber.subscribe(() -> playButton.disableProperty().unbind()); - } - - /** - * The method triggered by the start button. - * Creates a new game, modifies the username and displays the screen - */ - @FXML - private void start() { - String name = Utils.trim(nicknameField.getText(), Constants.MAX_NAME_LENGTH); - name = Utils.replaceIllegals(name); - Game game = this.gameService.createGame(name, (int) botAmountSlider.getValue()); - this.app.show("/ingame", Map.of("game", game)); - } - - @onDestroy - public void destroy() { - // Remove the card from the game - this.subscriber.dispose(); - } - - - @onInit - public void initSout() { - System.out.println(this + " initialized."); - } - - @onRender() - public void renderSout() { - System.out.println(this + " rendered."); - } - - @onDestroy - public void destroySout() { - System.out.println(this + " destroyed."); - } - - -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/dagger/MainComponent.java b/card-game/src/main/java/io/github/sekassel/uno/dagger/MainComponent.java deleted file mode 100644 index 99a46745..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/dagger/MainComponent.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.github.sekassel.uno.dagger; - -import dagger.BindsInstance; -import dagger.Component; -import io.github.sekassel.uno.App; -import io.github.sekassel.uno.UnoRouting; - -import javax.inject.Singleton; -import java.util.ResourceBundle; - -@Component(modules = {MainModule.class}) -@Singleton -public interface MainComponent { - - UnoRouting routes(); - - ResourceBundle bundle(); - - @Component.Builder - interface Builder { - @BindsInstance - Builder mainApp(App app); - - MainComponent build(); - } - -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/dagger/MainModule.java b/card-game/src/main/java/io/github/sekassel/uno/dagger/MainModule.java deleted file mode 100644 index b2498ecb..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/dagger/MainModule.java +++ /dev/null @@ -1,23 +0,0 @@ -package io.github.sekassel.uno.dagger; - -import dagger.Module; -import dagger.Provides; -import io.github.sekassel.uno.App; -import org.fulib.fx.FulibFxApp; - -import java.util.Locale; -import java.util.ResourceBundle; - -@Module -public class MainModule { - @Provides - FulibFxApp app(App app) { - return app; - } - - @Provides - ResourceBundle bundle() { - return ResourceBundle.getBundle("io/github/sekassel/uno/lang", Locale.GERMAN); - } - -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/model/Card.java b/card-game/src/main/java/io/github/sekassel/uno/model/Card.java deleted file mode 100644 index 33c4c291..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/model/Card.java +++ /dev/null @@ -1,158 +0,0 @@ -package io.github.sekassel.uno.model; - -import io.github.sekassel.uno.util.CardColor; -import io.github.sekassel.uno.util.CardType; - -import java.util.Objects; -import java.beans.PropertyChangeSupport; - -public class Card -{ - public static final String PROPERTY_COLOR = "color"; - public static final String PROPERTY_OWNER = "owner"; - public static final String PROPERTY_GAME = "game"; - public static final String PROPERTY_TYPE = "type"; - protected PropertyChangeSupport listeners; - private io.github.sekassel.uno.util.CardColor color = CardColor.WILD; - private Player owner; - private Game game; - private io.github.sekassel.uno.util.CardType type = CardType.ZERO; - - public io.github.sekassel.uno.util.CardColor getColor() - { - return this.color; - } - - public Card setColor(io.github.sekassel.uno.util.CardColor value) - { - if (Objects.equals(value, this.color)) - { - return this; - } - - final io.github.sekassel.uno.util.CardColor oldValue = this.color; - this.color = value; - this.firePropertyChange(PROPERTY_COLOR, oldValue, value); - return this; - } - - public Player getOwner() - { - return this.owner; - } - - public Card setOwner(Player value) - { - - if (this.owner == value) - { - return this; - } - - final Player oldValue = this.owner; - if (this.owner != null) - { - this.owner = null; - oldValue.withoutCards(this); - } - this.owner = value; - if (value != null) - { - value.withCards(this); - } - this.firePropertyChange(PROPERTY_OWNER, oldValue, value); - return this; - } - - public Game getGame() - { - return this.game; - } - - public Card setGame(Game value) - { - if (this.game == value) - { - return this; - } - - final Game oldValue = this.game; - if (this.game != null) - { - this.game = null; - oldValue.withoutCards(this); - } - this.game = value; - if (value != null) - { - value.withCards(this); - } - this.firePropertyChange(PROPERTY_GAME, oldValue, value); - return this; - } - - public io.github.sekassel.uno.util.CardType getType() - { - return this.type; - } - - public Card setType(io.github.sekassel.uno.util.CardType value) - { - if (Objects.equals(value, this.type)) - { - return this; - } - - final io.github.sekassel.uno.util.CardType oldValue = this.type; - this.type = value; - this.firePropertyChange(PROPERTY_TYPE, oldValue, value); - return this; - } - - public boolean firePropertyChange(String propertyName, Object oldValue, Object newValue) - { - if (this.listeners != null) - { - this.listeners.firePropertyChange(propertyName, oldValue, newValue); - return true; - } - return false; - } - - public PropertyChangeSupport listeners() - { - if (this.listeners == null) - { - this.listeners = new PropertyChangeSupport(this); - } - return this.listeners; - } - - public void removeYou() - { - this.setGame(null); - this.setOwner(null); - } - - /** - * Determines whether this card is compatible with another card (can be played on top of the other card). - * (Placed here for an easy way of checking card compatibility) - * - * @param below The card that would be below this card. - * @return Whether the card could be played. - */ - public boolean canBeOnTopOf(Card below) { - return below.getColor() == this.getColor() || this.getColor() == CardColor.WILD || below.getType() == this.getType(); - } - - public String toString() { // no fulib - return "[%s %s by %s in %s]".formatted(this.getName(), this.getColor(), this.getOwner(), this.getGame()); - } - - /** - * @return The name of the card - */ - public String getName() { - return this.getType().toString(); - } -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/model/Game.java b/card-game/src/main/java/io/github/sekassel/uno/model/Game.java deleted file mode 100644 index 7d69b608..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/model/Game.java +++ /dev/null @@ -1,251 +0,0 @@ -package io.github.sekassel.uno.model; - -import java.beans.PropertyChangeSupport; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - -public class Game -{ - public static final String PROPERTY_PLAYERS = "players"; - public static final String PROPERTY_CLOCKWISE = "clockwise"; - public static final String PROPERTY_CARDS = "cards"; - public static final String PROPERTY_CURRENT_PLAYER = "currentPlayer"; - public static final String PROPERTY_CURRENT_CARD = "currentCard"; - private List players; - protected PropertyChangeSupport listeners; - private boolean clockwise = true; - private List cards; - private Player currentPlayer; - private Card currentCard; - - public List getPlayers() - { - return this.players != null ? Collections.unmodifiableList(this.players) : Collections.emptyList(); - } - - public Game withPlayers(Player value) - { - if (this.players == null) - { - this.players = new ArrayList<>(); - } - if (!this.players.contains(value)) - { - this.players.add(value); - value.setGame(this); - this.firePropertyChange(PROPERTY_PLAYERS, null, value); - } - return this; - } - - public Game withPlayers(Player... value) - { - for (final Player item : value) - { - this.withPlayers(item); - } - return this; - } - - public Game withPlayers(Collection value) - { - for (final Player item : value) - { - this.withPlayers(item); - } - return this; - } - - public Game withoutPlayers(Player value) - { - if (this.players != null && this.players.remove(value)) - { - value.setGame(null); - this.firePropertyChange(PROPERTY_PLAYERS, value, null); - } - return this; - } - - public Game withoutPlayers(Player... value) - { - for (final Player item : value) - { - this.withoutPlayers(item); - } - return this; - } - - public Game withoutPlayers(Collection value) - { - for (final Player item : value) - { - this.withoutPlayers(item); - } - return this; - } - - public boolean isClockwise() - { - return this.clockwise; - } - - public Game setClockwise(boolean value) - { - if (value == this.clockwise) - { - return this; - } - - final boolean oldValue = this.clockwise; - this.clockwise = value; - this.firePropertyChange(PROPERTY_CLOCKWISE, oldValue, value); - return this; - } - - public List getCards() - { - return this.cards != null ? Collections.unmodifiableList(this.cards) : Collections.emptyList(); - } - - public Game withCards(Card value) - { - if (this.cards == null) - { - this.cards = new ArrayList<>(); - } - if (!this.cards.contains(value)) - { - this.cards.add(value); - value.setGame(this); - this.firePropertyChange(PROPERTY_CARDS, null, value); - } - return this; - } - - public Game withCards(Card... value) - { - for (final Card item : value) - { - this.withCards(item); - } - return this; - } - - public Game withCards(Collection value) - { - for (final Card item : value) - { - this.withCards(item); - } - return this; - } - - public Game withoutCards(Card value) - { - if (this.cards != null && this.cards.remove(value)) - { - value.setGame(null); - this.firePropertyChange(PROPERTY_CARDS, value, null); - } - return this; - } - - public Game withoutCards(Card... value) - { - for (final Card item : value) - { - this.withoutCards(item); - } - return this; - } - - public Game withoutCards(Collection value) - { - for (final Card item : value) - { - this.withoutCards(item); - } - return this; - } - - public Player getCurrentPlayer() - { - return this.currentPlayer; - } - - public Game setCurrentPlayer(Player value) - { - if (this.currentPlayer == value) - { - return this; - } - - final Player oldValue = this.currentPlayer; - this.currentPlayer = value; - this.firePropertyChange(PROPERTY_CURRENT_PLAYER, oldValue, value); - return this; - } - - public Card getCurrentCard() - { - return this.currentCard; - } - - public Game setCurrentCard(Card value) - { - if (this.currentCard == value) - { - return this; - } - - final Card oldValue = this.currentCard; - this.currentCard = value; - this.firePropertyChange(PROPERTY_CURRENT_CARD, oldValue, value); - return this; - } - - public boolean firePropertyChange(String propertyName, Object oldValue, Object newValue) - { - if (this.listeners != null) - { - this.listeners.firePropertyChange(propertyName, oldValue, newValue); - return true; - } - return false; - } - - public PropertyChangeSupport listeners() - { - if (this.listeners == null) - { - this.listeners = new PropertyChangeSupport(this); - } - return this.listeners; - } - - public void removeYou() - { - this.setCurrentPlayer(null); - this.setCurrentCard(null); - this.withoutCards(new ArrayList<>(this.getCards())); - this.withoutPlayers(new ArrayList<>(this.getPlayers())); - } - - /** - * Returns the first player of the game (which is always the human player when using game logic). - * (Placed here for an easy way of accessing the human player (or first player) of a game) - * - * @return The first player of the game - */ - public Player getFirstPlayer() { - return this.players.get(0); - } - - public String toString() { // no fulib - StringBuilder builder = new StringBuilder("["); - getPlayers().forEach(player -> builder.append(player).append(" ")); - return builder.substring(0, builder.length() - 1).toString() + "]"; - } -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/model/Player.java b/card-game/src/main/java/io/github/sekassel/uno/model/Player.java deleted file mode 100644 index 7c388968..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/model/Player.java +++ /dev/null @@ -1,185 +0,0 @@ -package io.github.sekassel.uno.model; - -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; - -import java.beans.PropertyChangeSupport; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Objects; - -public class Player -{ - public static final String PROPERTY_NAME = "name"; - public static final String PROPERTY_GAME = "game"; - public static final String PROPERTY_CARDS = "cards"; - public static final String PROPERTY_CURRENT_CARD = "currentCard"; - private String name; - private Game game; - protected PropertyChangeSupport listeners; - private ObservableList cards; - private Card currentCard; - - public String getName() - { - return this.name; - } - - public Player setName(String value) - { - if (Objects.equals(value, this.name)) - { - return this; - } - - final String oldValue = this.name; - this.name = value; - this.firePropertyChange(PROPERTY_NAME, oldValue, value); - return this; - } - - public Game getGame() - { - return this.game; - } - - public Player setGame(Game value) - { - if (this.game == value) - { - return this; - } - - final Game oldValue = this.game; - if (this.game != null) - { - this.game = null; - oldValue.withoutPlayers(this); - } - this.game = value; - if (value != null) - { - value.withPlayers(this); - } - this.firePropertyChange(PROPERTY_GAME, oldValue, value); - return this; - } - - public ObservableList getCards() - { - return this.cards != null ? cards : FXCollections.emptyObservableList(); - } - - public Player withCards(Card value) - { - if (this.cards == null) - { - this.cards = FXCollections.observableArrayList(); - } - if (!this.cards.contains(value)) - { - this.cards.add(value); - value.setOwner(this); - this.firePropertyChange(PROPERTY_CARDS, null, value); - } - return this; - } - - public Player withCards(Card... value) - { - for (final Card item : value) - { - this.withCards(item); - } - return this; - } - - public Player withCards(Collection value) - { - for (final Card item : value) - { - this.withCards(item); - } - return this; - } - - public Player withoutCards(Card value) - { - if (this.cards != null && this.cards.remove(value)) - { - value.setOwner(null); - this.firePropertyChange(PROPERTY_CARDS, value, null); - } - return this; - } - - public Player withoutCards(Card... value) - { - for (final Card item : value) - { - this.withoutCards(item); - } - return this; - } - - public Player withoutCards(Collection value) - { - for (final Card item : value) - { - this.withoutCards(item); - } - return this; - } - - public Card getCurrentCard() - { - return this.currentCard; - } - - public Player setCurrentCard(Card value) - { - if (this.currentCard == value) - { - return this; - } - - final Card oldValue = this.currentCard; - this.currentCard = value; - this.firePropertyChange(PROPERTY_CURRENT_CARD, oldValue, value); - return this; - } - - public boolean firePropertyChange(String propertyName, Object oldValue, Object newValue) - { - if (this.listeners != null) - { - this.listeners.firePropertyChange(propertyName, oldValue, newValue); - return true; - } - return false; - } - - public PropertyChangeSupport listeners() - { - if (this.listeners == null) - { - this.listeners = new PropertyChangeSupport(this); - } - return this.listeners; - } - - @Override - public String toString() - { - final StringBuilder result = new StringBuilder(); - result.append(' ').append(this.getName()); - return result.substring(1); - } - - public void removeYou() - { - this.setGame(null); - this.withoutCards(new ArrayList<>(this.getCards())); - this.setCurrentCard(null); - } -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/service/BotService.java b/card-game/src/main/java/io/github/sekassel/uno/service/BotService.java deleted file mode 100644 index 92888c17..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/service/BotService.java +++ /dev/null @@ -1,91 +0,0 @@ -package io.github.sekassel.uno.service; - -import dagger.Lazy; -import io.github.sekassel.uno.Constants; -import io.github.sekassel.uno.model.Card; -import io.github.sekassel.uno.model.Player; -import io.github.sekassel.uno.util.CardColor; -import io.github.sekassel.uno.util.Utils; -import javafx.application.Platform; - -import javax.inject.Inject; -import javax.inject.Singleton; -import javax.swing.*; -import java.util.List; -import java.util.Random; - -@Singleton -public class BotService { - - private final Random random; - - @Inject - Lazy gameService; - - @Inject - public BotService() { - this.random = new Random(); - } - - /** - * Makes a bot play a round after a certain delay. - * - * @param bot The bot which should play - */ - public void startTurn(Player bot) { - Timer timer = new Timer(Constants.BOT_PLAY_DELAY, task -> Platform.runLater(() -> this.playRound(bot))); - timer.setInitialDelay(Constants.BOT_PLAY_DELAY); - timer.setRepeats(false); - timer.restart(); //TODO: Fix timer not being stopped when game is closed by "Quit" button - } - - /** - * Selects a random cart out of the bot's cards which can be played - * - * @param bot The bot from which a card should be picked - * @return A card which can be played or null - */ - public Card selectCardToPlay(Player bot) { - Card current = bot.getGame().getCurrentCard(); - List possibleCards = bot.getCards().stream().filter(card -> card.canBeOnTopOf(current)).toList(); - return possibleCards.isEmpty() ? null : possibleCards.get(random.nextInt(possibleCards.size())); - } - - /** - * Selects a card and plays it. If no card can be found, a card will be drawn. - * If there is still no playable card, the next player will be selected. - * - * @param bot The bot which should play a card - */ - private void playRound(Player bot) { - Card selected = selectCardToPlay(bot); - - // If no card can be selected, draw a card - if (selected == null) { - Card drawn = this.gameService.get().handoutCards(bot, 1).get(0); - if (!drawn.canBeOnTopOf(bot.getGame().getCurrentCard())) { - this.gameService.get().selectNextPlayer(bot.getGame(), 1); - Utils.playSound(Constants.SOUND_FAIL); - return; - } - selected = drawn; - } - - CardColor color = selected.getColor(); - - // If the card is a wildcard, select a random color - color = color == CardColor.WILD ? Utils.getRandomColor(this.random) : null; - - // Play the card - gameService.get().playRound(selected, color); - } - - /** - * Removes a bot from the game. - * @param player The bot to remove - */ - public void removeBot(Player player) { - player.removeYou(); - } - -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/service/CardService.java b/card-game/src/main/java/io/github/sekassel/uno/service/CardService.java deleted file mode 100644 index a4a5bfc5..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/service/CardService.java +++ /dev/null @@ -1,63 +0,0 @@ -package io.github.sekassel.uno.service; - -import io.github.sekassel.uno.model.Card; -import io.github.sekassel.uno.model.Game; -import io.github.sekassel.uno.model.Player; -import io.github.sekassel.uno.util.CardColor; -import io.github.sekassel.uno.util.CardType; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.Random; - -@Singleton -public class CardService { - - private final Random random; - - @Inject - public CardService() { - this.random = new Random(); - } - - /** - * Generates a card and gives it to the player - * - * @param player The player which should receive a card - * @return The card given to the player - */ - public Card giveCardTo(Player player) { - return generateCard(player.getGame()).setOwner(player); - } - - /** - * Creates a random card - * - * @return The random card - */ - public Card generateCard(Game game) { - // Generate a random number (common or special) - int num = this.random.nextInt(CardType.values().length); - - // If the card isn't a wild card, pick a random color - CardColor color; - if (CardType.values()[num] == CardType.WILD) { - color = CardColor.WILD; - } else { - int colorNum = this.random.nextInt(CardColor.values().length - 1); - color = CardColor.values()[colorNum]; - } - - // Generate the card and return it - return new Card().setColor(color).setType(CardType.values()[num]).setGame(game); - - } - - /** - * @return The currently used random instance. - */ - public Random getRandom() { - return this.random; - } - -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/service/GameService.java b/card-game/src/main/java/io/github/sekassel/uno/service/GameService.java deleted file mode 100644 index e9f6cfd7..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/service/GameService.java +++ /dev/null @@ -1,203 +0,0 @@ -package io.github.sekassel.uno.service; - -import io.github.sekassel.uno.Constants; -import io.github.sekassel.uno.model.Card; -import io.github.sekassel.uno.model.Game; -import io.github.sekassel.uno.model.Player; -import io.github.sekassel.uno.util.CardColor; -import io.github.sekassel.uno.util.CardType; -import io.github.sekassel.uno.util.Utils; - -import javax.inject.Inject; -import javax.inject.Singleton; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -@Singleton -public class GameService { - - @Inject - CardService cardService; - @Inject - BotService botService; - - private final Random random; - - @Inject - public GameService() { - this.random = new Random(); - } - - /** - * Creates a game with a player and a certain number of bots. - * - * @param playerName The name of the player - * @param bots The amount of bots - * @return The created game - */ - public Game createGame(String playerName, int bots) { - Player player = new Player().setName(playerName); - - // Initialize the game with the human as the current player - Game game = new Game().setClockwise(true).withPlayers(player).setCurrentPlayer(player); - - // Create bots - for (int i = 1; i <= bots; i++) { - game.withPlayers(new Player().setName(Constants.BOT_NAME.formatted(i))); - } - - return game; - } - - /** - * Hands out cards to every player and selects a random start card. - * - * @param game The game to initialize - */ - public void initialize(Game game) { - - // Handout cards to every player - game.getPlayers().forEach(player -> handoutCards(player, Constants.START_CARD_AMOUNT)); - - // Generate a card and give it a random color if it's a wild card - Card firstCard = cardService.generateCard(game); - if (firstCard.getType() == CardType.WILD) { - firstCard.setColor(Utils.getRandomColor(this.random)); - } - - // Place the card - game.setCurrentCard(firstCard); - - } - - /** - * Hands out cards to a player. - * - * @param player The player which should receive cards - * @param amount The amount of cards - * @return The cards given to the player - */ - public List handoutCards(Player player, int amount) { - List cards = new ArrayList<>(); - for (int i = 0; i < amount; i++) { - cards.add(cardService.giveCardTo(player)); - } - return cards; - } - - public void selectCard(Card card) { - card.getOwner().setCurrentCard(card); - } - - /** - * Plays a given card as a given color and run its special effects. - * - * @param card The card to play - * @param color The color to play the card as (if null, the color will not be changed) - */ - public void playRound(Card card, CardColor color) { - - Game game = card.getGame(); - Card current = game.getCurrentCard(); - - if (!card.canBeOnTopOf(current)) { - return; - } - - if (color != null) { - card.setColor(color); - } - - Utils.playSound(Constants.SOUND_CLICK); - - // Remove the card from the player - card.getOwner().setCurrentCard(null); - card.setOwner(null); - - // Delete the old card, as it will never appear again - game.withoutCards(current); - current.removeYou(); - - // Place the card - game.setCurrentCard(card); - - // Check for special cards - if (card.getType().hasAction()) { - card.getType().getAction().run(card, this); - } else { - selectNextPlayer(game, 1); - } - } - - - /** - * Updates the current player of a given game. - * - * @param game The game to update. - * @param amount The amount of players to go over (amount of players to skip plus one) - */ - public void selectNextPlayer(Game game, int amount) { - Player next = getNextPlayer(game, amount); - - Player current = game.getCurrentPlayer(); - game.setCurrentPlayer(next); - - // If the player stays the same, no event gets fired, so we have to call the method manually - if (current == next && next != game.getFirstPlayer()) { - getBotService().startTurn(next); - } - - } - - /** - * Returns the player which should play next. - * - * @param game The current game - * @param amount The amount of players to go over (amount of players to skip plus one) - * @return The next player - */ - public Player getNextPlayer(Game game, int amount) { - int nextIndex = getNextPlayerIndex(game, amount); - return game.getPlayers().get(nextIndex); - } - - /** - * Returns the index of the player which should play next. - * - * @param game The current game - * @param amount The amount of players to go over (amount of players to skip plus one) - * @return The index of the next player - */ - private int getNextPlayerIndex(Game game, int amount) { - int current = game.getPlayers().indexOf(game.getCurrentPlayer()); - int players = game.getPlayers().size(); - - if (game.isClockwise()) { - return (current + amount) % players; - } else { - return (current + players - amount) % players; - } - } - - /** - * @return The currently used bot service instance. - */ - public BotService getBotService() { - return botService; - } - - /** - * @return The currently used card service instance. - */ - public CardService getCardService() { - return cardService; - } - - /** - * @return The currently used random instance. - */ - public Random getRandom() { - return this.random; - } -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/util/ActionRunnable.java b/card-game/src/main/java/io/github/sekassel/uno/util/ActionRunnable.java deleted file mode 100644 index 1462ae8f..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/util/ActionRunnable.java +++ /dev/null @@ -1,16 +0,0 @@ -package io.github.sekassel.uno.util; - -import io.github.sekassel.uno.model.Card; -import io.github.sekassel.uno.service.GameService; - -/** - * Defines the behaviour of a card. - * Every aspect of the game can be accessed through the card instance. - * Every method can be accessed through the game service instance. - */ -@FunctionalInterface -public interface ActionRunnable { - - void run(Card card, GameService service); - -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/util/CardColor.java b/card-game/src/main/java/io/github/sekassel/uno/util/CardColor.java deleted file mode 100644 index b7ee6d7e..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/util/CardColor.java +++ /dev/null @@ -1,29 +0,0 @@ -package io.github.sekassel.uno.util; - -/** - * Defines the color a card can have. - * If no color string is defined, it will use the enum's name as the color. - */ -public enum CardColor { - - RED, - BLUE, - GREEN, - YELLOW, - WILD("GRAY"); - - private final String color; - - CardColor(String color) { - this.color = color; - } - - CardColor() { - this.color = this.name(); - } - - public String getColorString() { - return this.color; - } - -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/util/CardType.java b/card-game/src/main/java/io/github/sekassel/uno/util/CardType.java deleted file mode 100644 index 8c3b7a2f..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/util/CardType.java +++ /dev/null @@ -1,76 +0,0 @@ -package io.github.sekassel.uno.util; - -import io.github.sekassel.uno.Constants; - -/** - * Defines the (special) mechanic of a card. - * Number cards don't need any special mechanic and can therefore be defined as a plain enum instance. - * Cards with a special mechanic have an ActionRunnable which will be called. - */ -public enum CardType { - - ZERO, - ONE, - TWO, - THREE, - FOUR, - FIVE, - SIX, - SEVEN, - EIGHT, - NINE, - - REVERSE(Constants.COUNTER_CLOCKWISE_ICON, (card, service) -> { - var game = card.getGame(); - game.setClockwise(!game.isClockwise()); - if (game.getPlayers().size() > 2) { - service.selectNextPlayer(game, 1); - } else if (game.getCurrentPlayer() != card.getGame().getFirstPlayer()) { - service.selectNextPlayer(card.getGame(), 2); - } - }), - - SKIP(Constants.SKIP_ICON, ((card, service) -> service.selectNextPlayer(card.getGame(), 2))), - - DRAW_TWO(Constants.DRAW_TWO_ICON, ((card, service) -> { - var receiver = service.getNextPlayer(card.getGame(), 1); - service.handoutCards(receiver, 2); - service.selectNextPlayer(card.getGame(), 2); - })), - - WILD(Constants.WILD_ICON); - - private final String icon; - private ActionRunnable action; - - CardType() { - this.icon = String.valueOf(this.ordinal()); - } - - CardType(String icon) { - this.icon = icon; - } - - CardType(String icon, ActionRunnable action) { - this.icon = icon; - this.action = action; - } - - @Deprecated - public int getNumber() { - return this.ordinal(); - } - - public String getIcon() { - return this.icon; - } - - public boolean hasAction() { - return this.action != null; - } - - public ActionRunnable getAction() { - return this.action; - } - -} diff --git a/card-game/src/main/java/io/github/sekassel/uno/util/Utils.java b/card-game/src/main/java/io/github/sekassel/uno/util/Utils.java deleted file mode 100644 index 991b7912..00000000 --- a/card-game/src/main/java/io/github/sekassel/uno/util/Utils.java +++ /dev/null @@ -1,80 +0,0 @@ -package io.github.sekassel.uno.util; - -import io.github.sekassel.uno.Constants; -import javafx.scene.media.Media; -import javafx.scene.media.MediaPlayer; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.Random; - -public class Utils { - - /** - * Replaces all illegal characters in a String - * - * @param name The string which should be cleared of illegal items - * @return The string with all illegal characters replaced - */ - public static String replaceIllegals(String name) { - return name.replaceAll("[/\\\\:*?\"<>|]", "x"); // Needs 4 backslashes since it's a regex and java escape char - } - - /** - * Trims a string to a certain length. - * @param toTrim The string to trim. - * @param size The size to trim the string to. - * @return The trimmed string. - */ - public static String trim(String toTrim, int size) { - return toTrim.length() < size ? toTrim : toTrim.substring(0, size); - } - - /** - * Generates a random color by a given random instance. - * Every color except the last one (wild) can be selected. - * - * @param random The instance to use for the random selection - * @return A random color - */ - public static CardColor getRandomColor(Random random) { - return CardColor.values()[random.nextInt(CardColor.values().length - 1)]; - } - - public static String getCardStyle(CardColor color) { - return Constants.CARD_STYLE.formatted(color.getColorString()); - } - - /** - * Generates a random instance by loading a seed from a file. - * If no file is found or the seed in the file is invalid, generate an instance without a seed. - * - * @return The generated random instance - */ - public static Random getRandomBySeedFile() { - try { - File file = new File("seed.txt"); - if (file.exists()) - return new Random(Integer.parseInt(Files.readString(file.toPath()))); - } catch (IOException | NumberFormatException exception) { - System.out.println("Couldn't read seed from 'seed.txt'."); - } - return new Random(); - } - - /** - * Plays a media/sound. - * - * @param sound The sound to be played - */ - public static void playSound(Media sound) { - try { - new MediaPlayer(sound).play(); - } catch (IllegalStateException e) { - System.err.println("Tried to play sound whilst game was in test mode."); - } - } - - -} diff --git a/card-game/src/main/resources/io/github/sekassel/uno/controller/GameOver.fxml b/card-game/src/main/resources/io/github/sekassel/uno/controller/GameOver.fxml deleted file mode 100644 index ef9f012c..00000000 --- a/card-game/src/main/resources/io/github/sekassel/uno/controller/GameOver.fxml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/card-game/src/main/resources/io/github/sekassel/uno/controller/Ingame.fxml b/card-game/src/main/resources/io/github/sekassel/uno/controller/Ingame.fxml deleted file mode 100644 index 11561a6f..00000000 --- a/card-game/src/main/resources/io/github/sekassel/uno/controller/Ingame.fxml +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/card-game/src/main/resources/io/github/sekassel/uno/controller/Setup.fxml b/card-game/src/main/resources/io/github/sekassel/uno/controller/Setup.fxml deleted file mode 100644 index 0c01f1df..00000000 --- a/card-game/src/main/resources/io/github/sekassel/uno/controller/Setup.fxml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/card-game/src/main/resources/io/github/sekassel/uno/controller/sub/Bot.fxml b/card-game/src/main/resources/io/github/sekassel/uno/controller/sub/Bot.fxml deleted file mode 100644 index e02dad5e..00000000 --- a/card-game/src/main/resources/io/github/sekassel/uno/controller/sub/Bot.fxml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/card-game/src/main/resources/io/github/sekassel/uno/controller/sub/Buttons.fxml b/card-game/src/main/resources/io/github/sekassel/uno/controller/sub/Buttons.fxml deleted file mode 100644 index 07af5702..00000000 --- a/card-game/src/main/resources/io/github/sekassel/uno/controller/sub/Buttons.fxml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/card-game/src/main/resources/io/github/sekassel/uno/controller/sub/Card.fxml b/card-game/src/main/resources/io/github/sekassel/uno/controller/sub/Card.fxml deleted file mode 100644 index 73263c66..00000000 --- a/card-game/src/main/resources/io/github/sekassel/uno/controller/sub/Card.fxml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - diff --git a/card-game/src/main/resources/io/github/sekassel/uno/image/logo.png b/card-game/src/main/resources/io/github/sekassel/uno/image/logo.png deleted file mode 100644 index 7ec0115b..00000000 Binary files a/card-game/src/main/resources/io/github/sekassel/uno/image/logo.png and /dev/null differ diff --git a/card-game/src/main/resources/io/github/sekassel/uno/lang_de.properties b/card-game/src/main/resources/io/github/sekassel/uno/lang_de.properties deleted file mode 100644 index dfe2e3df..00000000 --- a/card-game/src/main/resources/io/github/sekassel/uno/lang_de.properties +++ /dev/null @@ -1 +0,0 @@ -title=Uno \ No newline at end of file diff --git a/card-game/src/main/resources/io/github/sekassel/uno/sound/click.mp3 b/card-game/src/main/resources/io/github/sekassel/uno/sound/click.mp3 deleted file mode 100644 index c66b7954..00000000 Binary files a/card-game/src/main/resources/io/github/sekassel/uno/sound/click.mp3 and /dev/null differ diff --git a/card-game/src/main/resources/io/github/sekassel/uno/sound/fail.mp3 b/card-game/src/main/resources/io/github/sekassel/uno/sound/fail.mp3 deleted file mode 100644 index c4dbaf37..00000000 Binary files a/card-game/src/main/resources/io/github/sekassel/uno/sound/fail.mp3 and /dev/null differ diff --git a/card-game/src/main/scenarios/.gitkeep b/card-game/src/main/scenarios/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/card-game/src/test/java/io/github/sekassel/fx/.gitkeep b/card-game/src/test/java/io/github/sekassel/fx/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/card-game/src/test/resources/io/github/sekassel/fx/.gitkeep b/card-game/src/test/resources/io/github/sekassel/fx/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/settings.gradle b/settings.gradle index a82ac71d..9a7cdd26 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,5 +3,4 @@ rootProject.name = projectName include "framework" include "annotation-processor" -include "card-game" include "ludo" \ No newline at end of file