Fix: all JavaDOC completed

This commit is contained in:
2026-06-14 20:24:04 +02:00
parent ad8bbd8dca
commit 9f985c8ea9
24 changed files with 397 additions and 142 deletions
@@ -18,7 +18,10 @@ public class ClientLauncherGUI {
System.setProperty("glass.win.uiScale", "1.0");
Application.launch(GUIApp.class, args);
}
//TODO
/**
* Inner {@link Application} subclass that wires the GUI to the client controller
* and hands off control to {@link GUI#start(Stage)}.
*/
public static class GUIApp extends Application {
@Override
public void start(Stage stage) throws Exception {
@@ -25,13 +25,13 @@ import static org.jline.builtins.Completers.TreeCompleter.node;
* Handles login, connects to the server, and drives the JLine-powered command loop.
*/
public class ClientLauncherTUI {
//TODO
/** TUI view shared with the client controller. */
private TUI view;
//TODO
/** JLine terminal used for all input/output. */
private Terminal terminal;
//TODO
/** Line reader used during active gameplay, with tab-completion wired. */
private LineReader gameReader;
//TODO
/** Username of the currently logged-in player; empty string before login. */
private String currentUsername = "";
private static final String BUILDING_DETAILS =
@@ -81,7 +81,12 @@ public class ClientLauncherTUI {
"HUNTERS — Adding a Hunter without the \uD83C\uDF56 icon: nothing. Adding a Hunter WITH the \uD83C\uDF56 icon:\n" +
" immediately take 1 \uD83C\uDF56 for each Hunter in your tribe (with or without the icon).\n" +
" During Hunt Event, take \uD83C\uDF56 and gain PP based on your Hunter count (see 'details events').";
//TODO
/**
* Launches the TUI client.
*
* @param args command-line arguments (unused).
* @throws InterruptedException if the thread is interrupted during startup.
*/
public static void main(String[] args) throws InterruptedException {
new ClientLauncherTUI().start();
}
@@ -132,7 +137,12 @@ public class ClientLauncherTUI {
}
}
}
//TODO
/**
* Prompts for username, player count, network type, and server IP, then connects.
*
* @param controller the client controller to connect.
* @return {@code true} on successful connection; {@code false} if input is invalid or connection fails.
*/
private boolean doLogin(ClientController controller) {
LineReader loginReader = LineReaderBuilder.builder()
.terminal(terminal)
@@ -202,7 +212,12 @@ public class ClientLauncherTUI {
}
return true;
}
//TODO
/**
* Builds the JLine {@link LineReader} used during gameplay, with tab-completion
* for all valid commands.
*
* @return the configured {@link LineReader}.
*/
private LineReader buildGameReader() {
Completer completer = new TreeCompleter(
node("slot"),
@@ -227,7 +242,12 @@ public class ClientLauncherTUI {
.option(LineReader.Option.DISABLE_EVENT_EXPANSION, true)
.build();
}
//TODO
/**
* Returns the command-line prompt string showing the current username.
*
* @param controller the client controller (reserved for future use).
* @return the prompt string.
*/
private String buildPrompt(ClientController controller) {
return currentUsername.isEmpty() ? "> " : currentUsername + "> ";
}
@@ -279,7 +299,12 @@ public class ClientLauncherTUI {
}
return false;
}
//TODO
/**
* Handles the {@code draw} command, dispatching to the appropriate controller draw method.
*
* @param parts the tokenised command: {@code [draw, upper|lower, tribe|building, pos]}.
* @param controller the client controller to invoke.
*/
private void handleDraw(String[] parts, ClientController controller) {
if (parts.length < 4) {
view.showError(ErrorType.GENERIC_ERROR, "Usage: draw upper|lower tribe|building <pos>");
@@ -295,11 +320,21 @@ public class ClientLauncherTUI {
else if (tribe) controller.drawLowerTribeCard(pos);
else controller.drawLowerBuildingCard(pos);
}
//TODO
/**
* Handles the {@code clear} command by triggering a full board re-render.
*
* @param parts the tokenised command (only the command token is used).
*/
private void handleRender(String[] parts) {
view.renderBoard();
}
//TODO
/**
* Parses an integer position argument at {@code idx} in {@code parts}.
*
* @param parts the tokenised command array.
* @param idx index of the position argument.
* @return the parsed integer, or {@code -1} if missing or malformed.
*/
private int parsePos(String[] parts, int idx) {
if (parts.length <= idx) {
view.showError(ErrorType.GENERIC_ERROR, "Missing position argument.");
@@ -313,7 +348,11 @@ public class ClientLauncherTUI {
return -1;
}
}
//TODO
/**
* Disconnects the client if one is currently connected; safe to call when already disconnected.
*
* @param controller the client controller to disconnect.
*/
private void safeQuit(ClientController controller) {
if (controller.getClient() != null) controller.disconnect();
}
@@ -2,19 +2,39 @@ package it.polimi.ingsw.gc14;
/** Enumeration of error types that can be returned by server-side operations. */
public enum ErrorType {
/** The requested user does not exist. */
USER_NOT_FOUND("User not found"),
/** The chosen username is already taken by another connected player. */
USERNAME_ALREADY_USED("Username is already in use"),
/** The user is already connected to the server. */
USER_ALREADY_CONNECTED("User is already connected"),
/** The requested number of players is outside the allowed range. */
WRONG_PLAYER_NUMBER("Wrong player number"),
/** The server has crashed or become unreachable. */
SERVER_CRASHED("Server crashed"),
/** A generic, unclassified error occurred. */
GENERIC_ERROR("Generic error"),
/** The game has already started and cannot accept new players. */
GAME_ALREADY_STARTED("Game already started"),
/** The action attempted is not valid in the current game state. */
WRONG_ACTION("Wrong action");
//TODO
/** Human-readable description of this error, returned by {@link #toString()}. */
private final String description;
/**
* Creates an error type constant with the given human-readable description.
*
* @param description the message returned by {@link #toString()}.
*/
ErrorType(String description) {
this.description = description;
}
/**
* Returns the human-readable description of this error.
*
* @return the error description string.
*/
@Override
public String toString() {
return description;
@@ -50,7 +50,7 @@ public class GameEventProcessor {
/**
* Handle to the running forfeit timer, or {@code null} when no timer is active.
* A non-null value signals that the game is in the {@em suspended} state.
* A non-null value signals that the game is in the suspended state.
*/
private ScheduledFuture<?> disconnectionTimer;
@@ -21,13 +21,21 @@ public class ShamanicRitual extends EventCard {
/** Prestige points awarded to the player with the most shaman icons. */
private int prestigeToAdd;
// TODO
/**
* Returns the prestige points awarded to the player with the most shaman icons.
*
* @return prestige points to award.
*/
int getPrestigeToAdd() { return prestigeToAdd; }
/** Prestige points removed from the player with the fewest shaman icons. */
private int prestigeToRemove;
// TODO
/**
* Returns the prestige points removed from the player with the fewest shaman icons.
*
* @return prestige points to remove.
*/
int getPrestigeToRemove() { return prestigeToRemove; }
/**
@@ -72,7 +72,7 @@ public class Board implements Serializable {
*/
public List<BuildingCard> getLowerListBuilding() { return lowerListBuilding; }
// TODO
/** All building card lists grouped by era; index 0 = era 1, index 1 = era 2, etc. */
private final ArrayList<List<BuildingCard>> buildingCardsAllEras;
/** Number of players */
private int nTotem;
@@ -200,7 +200,12 @@ public class CurrentState implements Serializable {
}
// TODO
/**
* Returns a formatted ASCII table representation of the current game state.
* Columns: Player, Round, Era, GameStage.
*
* @return a {@code String} containing the ASCII table.
*/
@Override
public String toString(){
var table= new AsciiTable(BorderStyle.ROUNDED,4);
@@ -67,9 +67,17 @@ public abstract class PlayableCard implements Serializable {
}
}
/** Returns the compact representation shown in the player hand panel. */
/**
* Returns the compact representation shown in the player hand panel.
*
* @return the player-hand string representation of this card.
*/
public abstract String toStringPlayer();
/** Returns the representation shown on the board (offer track cards). */
/**
* Returns the representation shown on the board (offer track cards).
*
* @return the board string representation of this card.
*/
public abstract String toStringBoard();
}
@@ -31,7 +31,7 @@ public class Player implements Serializable {
// region Getters
/**
* Unique string identifier for players; must not be {@code null} and must not
* exceed {@link #MAX_VALUE} otherwise an {@link IllegalArgumentException} will be thrown
* exceed {@link #MAX_USERNAME_LENGTH} otherwise an {@link IllegalArgumentException} will be thrown
* when the {@link #Player(String) constructor} is called.
*/
private final String userName;
@@ -224,7 +224,13 @@ public class Player implements Serializable {
// region Functions
// TODO
/**
* Checks equality between this {@code Player} and another object.
* Two players are equal if and only if they share the same {@code userName}.
*
* @param obj the object to compare with.
* @return {@code true} if {@code obj} is a {@code Player} with the same username; {@code false} otherwise.
*/
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
@@ -178,7 +178,13 @@ public class Slot implements Serializable {
// Functions
// TODO
/**
* Checks equality between this {@code Slot} and another object.
* Two slots are equal if and only if they share the same {@code slotId}.
*
* @param obj the object to compare with.
* @return {@code true} if {@code obj} is a {@code Slot} with the same identifier; {@code false} otherwise.
*/
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
@@ -186,7 +192,11 @@ public class Slot implements Serializable {
return slotId == ((Slot) obj).slotId;
}
// TODO
/**
* Returns the hash code for this {@code Slot}, derived from {@link #slotId}.
*
* @return the hash code of the slot identifier.
*/
@Override
public int hashCode() {
return Character.hashCode(slotId);
@@ -30,6 +30,8 @@ public class CompositeClientBroadcaster {
* Forwards the event to both the RMI and the TCP server.
* Each server is responsible for filtering error events to the
* requesting player only.
*
* @param event the network event to broadcast.
*/
public void notifyAll(NetworkEvent event) {
rmiServer.notifyAll(event);
@@ -38,6 +40,8 @@ public class CompositeClientBroadcaster {
/**
* Forwards the model snapshot to every client on both transports.
*
* @param model the mini model snapshot to broadcast.
*/
public void notifyAll(MiniModel model) {
rmiServer.notifyAll(model);
@@ -19,7 +19,7 @@ import java.util.List;
* during totem selection may free a totem for other players.
*/
public class DisconnectedPlayer extends NetworkEvent {
//TODO
/** Updated list of totems available after the disconnection frees any previously chosen totem. */
private List<Totems> availableTotems;
@@ -33,7 +33,7 @@ public class ClientCallbackImpl extends UnicastRemoteObject implements IClientCa
/**
* Called by the server when the game is initialized.
* Sets the client game model in the {@link ClientController}.
* @param model the initialized {@link Game} model
* @param model the initialized {@link it.polimi.ingsw.gc14.Model.Game Game} model
* @throws RemoteException if any RMI error occurs
*/
@Override
@@ -68,7 +68,7 @@ public class TCPClient implements IClient {
* Otherwise, a listener thread is started.
* @param user The username of the player
* @param proposedNPlayers The desired number of players for the game
* @return true if the connection is successful, false otherwise.
* @return null if the connection is successful, GENERIC_ERROR otherwise.
*/
public ErrorType connect(String user, int proposedNPlayers) {
try {
@@ -11,23 +11,53 @@ import java.util.Iterator;
import java.util.List;
import java.util.Random;
//TODO ALL JAVADOC
/**
* Ambient fire-particle effect rendered on a transparent overlay pane.
*
* <p>Three particle types float from the screen corners toward the centre:
* <ul>
* <li><b>embers</b> (type 0) — slow, glowing orange circles with a soft halo.</li>
* <li><b>sparks</b> (type 1) — fast, short-lived bright particles.</li>
* <li><b>dust</b> (type 2) — large, translucent brown drifting circles.</li>
* </ul>
*
* <p>Call {@link #start()} after adding {@link #getPane()} to the scene graph,
* and {@link #stop()} when the scene is hidden.
*/
public class FireParticleSystem {
/** Maximum number of live particles at any given time. */
private static final int MAX_PARTICLES = 30;
/** Minimum nanoseconds between particle spawn batches. */
private static final long SPAWN_INTERVAL_NS = 100_000_000L;
private static final long FRAME_INTERVAL_NS = 1_000_000_000L / 30; // 30 fps cap
private static final int STEPS_PER_FRAME = 3; // physics steps per frame → 3× speed
/** Minimum nanoseconds between rendered frames (30 fps cap). */
private static final long FRAME_INTERVAL_NS = 1_000_000_000L / 30;
/** Physics update steps applied per rendered frame (multiplies effective speed). */
private static final int STEPS_PER_FRAME = 3;
/** Mouse-transparent overlay pane that hosts all particle nodes. */
private final Pane pane;
/** The scene whose dimensions are used to position and fade particles. */
private final Scene scene;
/** Currently live particles. */
private final List<Particle> particles = new ArrayList<>();
/** Shared random source for particle initialisation and physics noise. */
private final Random rnd = new Random();
/** The JavaFX animation timer driving the particle loop. */
private AnimationTimer timer;
/** Timestamp (ns) of the last particle spawn batch. */
private long lastSpawn = 0;
/** Timestamp (ns) of the last rendered frame. */
private long lastFrame = 0;
/** {@code true} after the first tick pre-populates the particle pool. */
private boolean warmedUp = false;
/**
* Creates the particle system bound to the given scene.
* The internal overlay pane is transparent and mouse-transparent.
*
* @param scene the scene whose dimensions are used for particle positioning and fading.
*/
public FireParticleSystem(Scene scene) {
this.scene = scene;
pane = new Pane();
@@ -35,7 +65,11 @@ public class FireParticleSystem {
pane.setPickOnBounds(false);
}
/** Returns the transparent overlay pane that holds all particle nodes. */
/**
* Returns the transparent overlay pane that holds all particle nodes.
*
* @return the mouse-transparent {@link Pane} overlay.
*/
public Pane getPane() { return pane; }
/** Starts the animation timer. */
@@ -56,6 +90,12 @@ public class FireParticleSystem {
if (timer != null) timer.stop();
}
/**
* Advances the simulation by one frame: pre-warms on first call, spawns new particles,
* steps existing ones, removes dead ones, and updates their visual state.
*
* @param now the current timestamp in nanoseconds from the animation timer.
*/
private void tick(long now) {
double w = scene.getWidth();
double h = scene.getHeight();
@@ -98,6 +138,13 @@ public class FireParticleSystem {
}
}
/**
* Creates a new particle starting near one of the four screen corners.
*
* @param w scene width in pixels.
* @param h scene height in pixels.
* @return the newly constructed {@link Particle}.
*/
private Particle spawnParticle(double w, double h) {
int corner = rnd.nextInt(4);
double margin = 0.12;
@@ -113,18 +160,51 @@ public class FireParticleSystem {
// ── Particle ──────────────────────────────────────────────────────────────
/**
* A single fire particle with position, velocity, wobble, and JavaFX visual nodes.
* Particles are typed: 0 = ember, 1 = spark, 2 = dust.
*/
private static class Particle {
double x, y, vx, vy;
/** Current X position in scene pixels. */
double x;
/** Current Y position in scene pixels. */
double y;
/** Horizontal velocity component. */
double vx;
/** Vertical velocity component. */
double vy;
/** Remaining life fraction (1.0 = full, 0.0 = dead); only decrements for sparks. */
double life;
/** Visual radius of the particle's core circle. */
double size;
double wobblePhase, wobbleSpeed, wobbleAmp;
/** Current phase of the sinusoidal wobble. */
double wobblePhase;
/** Angular speed of the wobble oscillation. */
double wobbleSpeed;
/** Amplitude factor of the wobble displacement. */
double wobbleAmp;
/** Particle type: 0 = ember, 1 = spark, 2 = dust. */
final int type;
/** Shared random source used during physics updates. */
final Random rnd;
/** Primary visible circle node. */
final Circle core;
final Circle glow; // non-null only for embers
/** Soft glow halo circle behind {@link #core}; non-null only for embers (type 0). */
final Circle glow;
/**
* Initialises the particle at position ({@code x}, {@code y}) with velocity
* aimed roughly from the given {@code corner} toward the scene centre.
*
* @param x spawn X coordinate.
* @param y spawn Y coordinate.
* @param w scene width (used to compute target direction).
* @param h scene height (used to compute target direction).
* @param corner spawn corner index: 0 = bottom-left, 1 = bottom-right, 2 = top-left, 3 = top-right.
* @param rnd shared random source.
*/
Particle(double x, double y, double w, double h, int corner, Random rnd) {
this.x = x;
this.y = y;
@@ -163,6 +243,12 @@ public class FireParticleSystem {
wobbleAmp = 0.1 + rnd.nextDouble() * 0.4;
}
/**
* Returns a particle type weighted toward embers (55% ember, 23% spark, 22% dust).
*
* @param rnd the random source.
* @return particle type: 0, 1, or 2.
*/
private static int weightedType(Random rnd) {
double r = rnd.nextDouble();
if (r < 0.55) return 0;
@@ -170,16 +256,27 @@ public class FireParticleSystem {
return 2;
}
/**
* Adds this particle's visual nodes to {@code pane} (glow first so core renders on top).
*
* @param pane the overlay pane to add nodes to.
*/
void addTo(Pane pane) {
if (glow != null) pane.getChildren().add(glow);
pane.getChildren().add(core);
}
/**
* Removes this particle's visual nodes from {@code pane}.
*
* @param pane the overlay pane to remove nodes from.
*/
void removeFrom(Pane pane) {
pane.getChildren().remove(core);
if (glow != null) pane.getChildren().remove(glow);
}
/** Advances this particle by one physics step: applies wobble, moves, and decrements spark life. */
void update() {
wobblePhase += wobbleSpeed;
vx += Math.sin(wobblePhase) * wobbleAmp * 0.05;
@@ -189,12 +286,26 @@ public class FireParticleSystem {
if (type == 1) life -= 0.008 + rnd.nextDouble() * 0.006;
}
/**
* Returns {@code true} when this particle has left the scene bounds or, for sparks, its life reached zero.
*
* @param w scene width.
* @param h scene height.
* @return {@code true} if the particle should be removed.
*/
boolean isDead(double w, double h) {
double pad = size * 4;
return x < -pad || x > w + pad || y < -pad || y > h + pad
|| (type == 1 && life <= 0);
}
/**
* Updates color, opacity, and translate position of this particle's visual nodes
* based on distance from scene edges and remaining life.
*
* @param w scene width.
* @param h scene height.
*/
void updateVisual(double w, double h) {
double edge = Math.min(w, h) * 0.05;
double fadeX = Math.min(x / edge, Math.min((w - x) / edge, 1.0));
@@ -33,43 +33,41 @@ import static it.polimi.ingsw.gc14.Model.GamePackage.GameStages.TOTEM_CHOICE;
* main game, and leaderboard scenes based on the current game state.
*/
public class GUI extends Application implements IView {
//TODO
/** The primary JavaFX stage. */
private Stage primaryStage;
//TODO
/** Latest mini model received from the server. */
private volatile MiniModel miniModel;
//TODO
/** FXML loader for the login scene. */
private FXMLLoader loaderLogin;
//TODO
/** The login scene. */
private Scene loginScene;
//TODO
/** Controller for the login FXML scene. */
private LoginFXMLController controllerLogin;
//TODO
/** FXML loader for the totem selection scene. */
private FXMLLoader loaderTotem;
//TODO
/** The totem selection scene. */
private Scene totemScene;
//TODO
/** Controller for the totem FXML scene. */
private TotemFXMLController controllerTotem;
//TODO
/** FXML loader for the main game scene. */
private FXMLLoader loaderMain;
//TODO
/** The main game scene. */
private Scene mainScene;
//TODO
/** Controller for the main FXML scene. */
private MainFXMLController controllerMain;
//TODO
/** FXML loader for the leaderboard scene. */
private FXMLLoader loaderLeaderboard;
//TODO
/** The end-of-game leaderboard scene. */
private Scene leaderboardScene;
//TODO
/** Controller for the leaderboard FXML scene. */
private LeaderboardFXMLController controllerLeaderboard;
//TODO
/** Client controller injected before JavaFX startup. */
private ClientController controller;
//TODO
/** When {@code true}, the app re-enters fullscreen automatically after ESC is pressed. */
private boolean autoReenterFullscreen = true;
//TODO
/** Guards against overlapping fade transitions. */
private boolean isFading = false;
//TODO
/** Background music player looping indefinitely. */
private MediaPlayer bgMusic;
@@ -208,12 +206,22 @@ public class GUI extends Application implements IView {
}
});
}
//TODO
/**
* Wraps the current root of {@code scene} in a {@link StackPane} so that
* fade overlay rectangles can be layered over it during scene transitions.
*
* @param scene the scene whose root to wrap.
*/
private void wrapScene(Scene scene) {
Parent root = scene.getRoot();
scene.setRoot(new StackPane(root));
}
//TODO
/**
* Performs a black-overlay crossfade from the current scene to {@code newScene}.
* No-op if already fading or if {@code newScene} is already displayed.
*
* @param newScene the scene to transition to.
*/
private void fadeToScene(Scene newScene) {
Scene currentScene = primaryStage.getScene();
if (currentScene == newScene || isFading) return;
@@ -41,18 +41,17 @@ public class LeaderboardFXMLController {
@FXML private VBox mainVBox;
@FXML private VBox rankingList;
// title label removed; outcome text is added dynamically in render()
//TODO
/** Client controller for fetching game state and sending actions. */
private ClientController controller;
//TODO
/** Auto-hiding popup that shows detailed player card information. */
private Popup popup;
//TODO
/** Content container inside {@link #popup}. */
private VBox popupContent;
//TODO
/** Shared image cache to avoid reloading resources multiple times. */
private static final Map<String, Image> imageCache = new HashMap<>();
//TODO
/** The login scene shown when the player starts a new game. */
private Scene loginScene;
//TODO
/** Action run when the player returns to the login screen (disconnect + scene switch). */
private Runnable action;
/** Returns a cached {@link Image} for the given classpath {@code path}, loading it on first access. */
@@ -29,33 +29,33 @@ import java.util.Enumeration;
* and initiates the connection to the server.
*/
public class LoginFXMLController {
//TODO
/** Background image displayed behind the login form. */
@FXML private ImageView backgroundImage;
//TODO
/** Text field for the player's username. */
@FXML private TextField campoNome;
//TODO
/** Text field for the desired number of players. */
@FXML private TextField campoNumPlayers;
//TODO
/** Text field for the server IP address. */
@FXML private TextField campoIP;
//TODO
/** Button that submits the login form. */
@FXML private Button btnAccedi;
//TODO
/** Label used to show error or success messages. */
@FXML private Label labelErrore;
//TODO
/** VBox containing the login form controls. */
@FXML private VBox formPanel;
//TODO
/** Toggle container for switching between RMI and TCP. */
@FXML private StackPane protocolToggle;
//TODO
/** Sliding thumb inside the protocol toggle. */
@FXML private Region toggleThumb;
//TODO
/** Label for the RMI side of the protocol toggle. */
@FXML private Label labelRMI;
//TODO
/** Label for the TCP side of the protocol toggle. */
@FXML private Label labelTCP;
//TODO
/** {@code true} when RMI is selected; {@code false} for TCP. */
private boolean isRMI = true;
//TODO
/** Client controller used to initiate the connection. */
private ClientController controller;
//TODO
/** CSS pseudo-class applied to the active protocol label. */
private final PseudoClass activeProtocolPseudo = PseudoClass.getPseudoClass("active-protocol");
/**
@@ -46,47 +46,51 @@ import java.util.*;
* the player's hand, and action buttons (skip, details).
*/
public class MainFXMLController {
//TODO
/** Left column grid used for the board slots layout. */
@FXML private GridPane leftGrid;
//TODO
/** Scrollable container holding all player side-panel cards. */
@FXML private ScrollPane playerSide;
//TODO
/** Root HBox containing all main scene elements. */
@FXML private HBox mainHBox;
//TODO
/** Background image view for the main scene. */
@FXML private ImageView backgroundImage;
//TODO
/** HBox holding the board slot and order cards. */
@FXML private HBox board;
//TODO
/** HBox holding the upper tribe card row (and upper building stack). */
@FXML private HBox upperList;
//TODO
/** HBox holding the lower tribe card row (and lower building stack). */
@FXML private HBox lowerList;
//TODO
/** HBox displaying the local player's card piles. */
@FXML private HBox myHand;
//TODO
/** Button that sends a skip-turn command. */
@FXML private Button skipBtn;
//TODO
/** Button that opens the game details popup. */
@FXML private Button detailsBtn;
//TODO
/** Label showing the current round number and game stage. */
@FXML private Label infoText;
//TODO
/** Maps each player's username to their current food-value label in the side panel. */
private final Map<String, Label> foodLabels = new HashMap<>();
//TODO
/** Maps each player's username to their current prestige-value label in the side panel. */
private final Map<String, Label> prestigeLabels = new HashMap<>();
//TODO
/** Maps each player's username to their player-card VBox in the side panel. */
private final Map<String, VBox> playerCards = new HashMap<>();
//TODO
/** Maps each player's username to their ordered list of card-type icon ImageViews. */
private final Map<String, List<ImageView>> iconViews = new HashMap<>();
//TODO
/** Shared popup used for card previews and building selection. */
private Popup popup;
//TODO
/** HBox inside {@link #popup} that holds the displayed card images. */
private HBox popupCards;
//TODO
/** Client controller for fetching game state and sending player actions. */
private ClientController controller;
/** {@code true} when the last received event was an error response. */
private boolean isError;
/** Sets the error flag; called by {@link GUI} before delegating to {@link #render()}. */
/**
* Sets the error flag; called by {@link GUI} before delegating to {@link #render()}.
*
* @param error {@code true} if the last received event was an error response.
*/
public void setError(boolean error) { this.isError = error; }
// ==== IMAGE CACHE ====
@@ -24,20 +24,20 @@ import java.util.Locale;
* other players see a waiting banner.
*/
public class TotemFXMLController {
//TODO
/** Background image displayed behind the totem selection grid. */
@FXML private ImageView backgroundImage;
//TODO
/** HBox containing the totem card widgets. */
@FXML private HBox mainHBox;
//TODO
/** Banner label showing whose turn it is to choose a totem. */
@FXML private Label turnBanner;
//TODO
/** Button that submits the selected totem to the server. */
@FXML private Button confirmButton;
//TODO
/** Client controller for sending the totem choice. */
private ClientController controller;
//TODO
/** Index of the currently selected totem, or {@code -1} if none selected. */
private int selectedIndex = -1;
//TODO
/** The {@link StackPane} frame of the currently selected totem card, or {@code null}. */
private StackPane selectedFrame = null;
/**
@@ -21,33 +21,62 @@ import java.util.*;
* }</pre>
*/
public class AsciiTable {
//TODO
/** Border style used to draw corners, lines, and junctions. */
private final BorderStyle s;
//TODO
/** Number of columns in this table. */
private final int cols;
//TODO
/** All rows of the table, in insertion order. */
private final List<List<String>> rows = new ArrayList<>();
//TODO
/** Indices of rows after which a horizontal separator line is drawn. */
private final List<Integer> separators = new ArrayList<>();
//TODO
/**
* Creates a new empty table with the given border style and column count.
*
* @param s the border style to use when rendering.
* @param cols the number of columns.
*/
public AsciiTable(BorderStyle s, int cols) {
this.s = s; this.cols = cols;
}
//TODO
/**
* Appends a row using varargs cells.
*
* @param cells one value per column.
*/
public void addRow(String... cells) { rows.add(Arrays.asList(cells)); }
//TODO
/**
* Appends a row from an existing list.
*
* @param cells one value per column.
*/
public void addRow(List<String> cells) { rows.add(cells); }
//TODO
/**
* Inserts a header row at position 0 and marks it with a separator line below it.
*
* @param cells one header label per column.
*/
public void addHeader(String... cells) {
rows.add(0, Arrays.asList(cells));
separators.add(0);
}
//TODO
/**
* Marks a separator line to be drawn after the last row added so far.
*/
public void addSeparator() { separators.add(rows.size() - 1); }
/**
* Renders the table to a multi-line string.
* Column width is the widest cell in display columns (wide chars = 2), plus 1.
*
* @return the fully rendered table as a multi-line string.
*/
public String build() {
var sb = new StringBuilder();
@@ -67,7 +96,15 @@ public class AsciiTable {
sb.append(hline(s.bl(), s.mb(), s.br(), maxWidth));
return sb.toString();
}
//TODO
/**
* Builds a single horizontal border line across all columns.
*
* @param l left-end character.
* @param m middle junction character (between columns).
* @param r right-end character.
* @param maxWidth width in display columns of each cell (including padding).
* @return the rendered horizontal line string.
*/
private String hline(String l, String m, String r, int maxWidth) {
var sb = new StringBuilder(l);
for (int i = 0; i < cols; i++) {
@@ -91,6 +128,11 @@ public class AsciiTable {
* Places two pre-rendered text blocks side by side, separated by a gap.
* Left-block lines are padded to a uniform display width so the right block
* always starts at the same column. Uses {@link #displayWidth} for measurement.
*
* @param left lines of the left block.
* @param right lines of the right block.
* @param gap number of space characters between the two blocks.
* @return the combined multi-line string.
*/
public static String sideBySide(List<String> left, List<String> right, int gap) {
int leftWidth = left.stream().mapToInt(AsciiTable::displayWidth).max().orElse(0);
@@ -112,6 +154,9 @@ public class AsciiTable {
/**
* Returns the number of terminal columns required to display {@code s}.
* Wide characters (emoji, CJK, full-width) count as 2; all others as 1.
*
* @param s the string to measure; ANSI escape sequences are stripped before counting.
* @return the display width in terminal columns.
*/
public static int displayWidth(String s) {
s = s.replaceAll("\033\\[[^m]*m", "");
@@ -9,16 +9,6 @@ package it.polimi.ingsw.gc14.View.TUI;
*/
public enum BorderStyle {
/**
* Unicode box-drawing border style.
*/
UNICODE("","","","","","","","","","","","","",""),
/**
* Plain ASCII border style.
*/
ASCII ("+","+","+","+","-","|","+","+","+","+","+","+","+","+"),
/**
* Rounded Unicode border style.
*/
@@ -70,16 +60,6 @@ public enum BorderStyle {
*/
public String v() { return v; }
/**
* @return the middle-left junction character.
*/
public String ml() { return ml; }
/**
* @return the middle-right junction character.
*/
public String mr() { return mr; }
/**
* @return the top-middle junction character.
*/
@@ -90,11 +70,6 @@ public enum BorderStyle {
*/
public String mb() { return mb; }
/**
* @return the center junction character.
*/
public String x() { return x; }
/**
* @return the separator-left junction character.
*/
@@ -48,12 +48,20 @@ public class TUI implements IView {
// Setters
/** Sets the username of the local player. */
/**
* Sets the username of the local player.
*
* @param username the username to assign.
*/
public void setUsername(String username) {
this.username = username;
}
/** Updates the model stored in this view. */
/**
* Updates the model stored in this view.
*
* @param model the latest mini model to display.
*/
@Override
public void setModel(MiniModel model) {
this.model = model;
@@ -63,6 +71,8 @@ public class TUI implements IView {
* Registers the active JLine {@link LineReader}.
* Once set, all output routes through {@link LineReader#printAbove} so the
* prompt survives background-thread renders.
*
* @param lineReader the JLine reader to use for output; also provides the terminal reference.
*/
public void setLineReader(LineReader lineReader) {
this.lineReader = lineReader;
@@ -245,7 +245,7 @@ class BuildingCardTest {
assertEquals(food, p2.getFoodValue());
assertTrue(bc.buy(p2));
int discount = p2.getBuilders().stream().mapToInt(x -> x.getReductionValue()).sum();
p2.getBuilders().stream().mapToInt(x -> x.getReductionValue()).sum();
assertEquals(food, p2.getFoodValue());
p2.removeFood(p2.getFoodValue());