diff --git a/src/main/java/it/polimi/ingsw/gc14/View/TUI/AsciiTable.java b/src/main/java/it/polimi/ingsw/gc14/View/TUI/AsciiTable.java index 26ccb31..813708c 100644 --- a/src/main/java/it/polimi/ingsw/gc14/View/TUI/AsciiTable.java +++ b/src/main/java/it/polimi/ingsw/gc14/View/TUI/AsciiTable.java @@ -1,43 +1,112 @@ package it.polimi.ingsw.gc14.View.TUI; import java.util.*; -//TODO javadoc -// Helper generale per costruire tabelle ASCII +/** + * General-purpose helper for building fixed-width ASCII/Unicode tables in a TUI. + * + *
A table is built by adding rows one at a time, then calling {@link #build()} + * to obtain the fully rendered string. Column width is computed automatically + * from the widest cell across all rows. + * + *
Example usage: + *
{@code
+ * AsciiTable table = new AsciiTable(BorderStyle.UNICODE, 3);
+ * table.addHeader("Name", "Food", "PP");
+ * table.addRow("Alice", "4", "12");
+ * table.addRow("Bob", "2", "8");
+ * System.out.println(table.build());
+ * }
+ */
public class AsciiTable {
- //TODO javadoc
+
+ /**
+ * The border style used to draw the table (e.g. Unicode box-drawing,
+ * plain ASCII, rounded corners).
+ */
private final BorderStyle s;
- //TODO javadoc
+ /**
+ * The number of columns in the table.
+ * Every row added via {@link #addRow} must contain exactly this many cells.
+ */
private final int cols;
- //TODO javadoc
+ /**
+ * The rows of the table, each represented as a list of cell strings.
+ * Rows are stored in display order; {@link #addHeader} inserts at index 0.
+ */
private final ListCalling this method after rows have already been added will push + * all existing rows down by one position. + * + * @param cells one string per column, in left-to-right order + */ + public void addHeader(String... cells) { + rows.add(0, Arrays.asList(cells)); + separators.add(0); + } - //TODO javadoc - public void addSeparator() { separators.add(rows.size()-1); } + /** + * Marks the current last row so that a horizontal separator line is + * drawn below it when the table is built. + * + *
Call this method immediately after the row that should be followed + * by the separator. + */ + public void addSeparator() { separators.add(rows.size() - 1); } - //TODO javadoc + /** + * Renders the table to a multi-line string. + * + *
Column width is determined dynamically as the length of the longest + * cell across all rows, plus one padding space. All cells are left-aligned + * and padded or truncated to the same width. + * + * @return the fully rendered table as a single string with embedded newlines + */ public String build() { var sb = new StringBuilder(); - int maxWidth = rows.stream().mapToInt(x->x.stream().mapToInt(y->y.length()).max().getAsInt()).max().getAsInt()+1; - sb.append(hline(s.tl(), s.mt(), s.tr(),maxWidth)).append('\n'); + int maxWidth = rows.stream() + .mapToInt(x -> x.stream().mapToInt(y -> y.length()).max().getAsInt()) + .max().getAsInt() + 1; + sb.append(hline(s.tl(), s.mt(), s.tr(), maxWidth)).append('\n'); for (int i = 0; i < rows.size(); i++) { sb.append(s.v()); @@ -45,14 +114,23 @@ public class AsciiTable { sb.append(rpad(" " + cell, maxWidth)).append(s.v()); sb.append('\n'); if (separators.contains(i) && i < rows.size() - 1) - sb.append(hline(s.sl(), s.sx(), s.sr(),maxWidth)).append('\n'); + sb.append(hline(s.sl(), s.sx(), s.sr(), maxWidth)).append('\n'); } sb.append(hline(s.bl(), s.mb(), s.br(), maxWidth)); return sb.toString(); } - //TODO javadoc - private String hline(String l, String m, String r,int maxWidth) { + /** + * Builds a single horizontal border line spanning all columns. + * + * @param l the left-end character (e.g. {@code ╔}, {@code ╠}, {@code ╚}) + * @param m the column-junction character (e.g. {@code ╦}, {@code ╬}, {@code ╩}) + * @param r the right-end character (e.g. {@code ╗}, {@code ╣}, {@code ╝}) + * @param maxWidth the width in characters of each column segment, + * filled with the horizontal line character of the current style + * @return the rendered horizontal line as a string + */ + private String hline(String l, String m, String r, int maxWidth) { var sb = new StringBuilder(l); for (int i = 0; i < cols; i++) { sb.append(s.h().repeat(maxWidth)); @@ -61,13 +139,40 @@ public class AsciiTable { return sb.append(r).toString(); } - //TODO javadoc + /** + * Right-pads a string with spaces to the given width, or truncates it + * if it exceeds that width. + * + * @param s the input string + * @param w the desired output width in characters + * @return a string of exactly {@code w} characters + */ private static String rpad(String s, int w) { if (s.length() >= w) return s.substring(0, w); return s + " ".repeat(w - s.length()); } - //TODO javadoc + /** + * Places two pre-rendered text blocks side by side, separated by a gap. + * + *
Each block is a list of lines as returned by {@link #build()}. + * Lines in the left block are padded to a uniform width so that the + * right block always starts at the same horizontal position. If one + * block is taller than the other, the shorter one is padded with blank + * lines. + * + *
Example: + *
{@code
+ * List left = Arrays.asList(table1.build().split("\n"));
+ * List right = Arrays.asList(table2.build().split("\n"));
+ * System.out.print(AsciiTable.sideBySide(left, right, 2));
+ * }
+ *
+ * @param left lines of the left block
+ * @param right lines of the right block
+ * @param gap number of blank spaces between the two blocks
+ * @return the merged string with embedded newlines
+ */
public static String sideBySide(ListRenders the current state of a {@link Game} model directly to the + * standard output using Unicode box-drawing characters and fixed-width + * ASCII tables (see {@link AsciiTable}). + * + *
The display is split into two side-by-side panels: + *
The terminal is cleared before each render via a platform-aware + * {@code cls} / {@code clear} system call. + * + *
Typical usage: + *
{@code
+ * TUI tui = new TUI(game);
+ * tui.setUsername("Alice");
+ * tui.fullRender();
+ * }
+ */
public class TUI implements IView {
- // ── dati di stato ───────────────────────────────────────────
- private BorderStyle style = BorderStyle.UNICODE;
+ /**
+ * The {@link Game} model whose state is rendered.
+ * Updated via {@link #update(Game)} whenever the game state changes.
+ */
private Game model;
+
+ /**
+ * The username of the local player, used to retrieve and display
+ * that player's hand in the right panel.
+ *
+ * @see #setUsername(String)
+ */
private String username;
+
+ /**
+ * Constructs a {@code TUI} bound to the given game model.
+ * The username is initialised to an empty string and must be set
+ * separately via {@link #setUsername(String)} before calling any
+ * render method that displays the player's hand.
+ *
+ * @param model the {@link Game} model to display; must not be {@code null}
+ */
public TUI(Game model) {
this.model = model;
- this.username="";
+ this.username = "";
}
+
+ /**
+ * Sets the username of the local player.
+ * This value is used by {@link #renderBoard()} and {@link #fullRender()}
+ * to look up the correct player hand via
+ * {@link Game#getPlayerByUsername(String)}.
+ *
+ * @param username the player's username; must match an existing player
+ * in the current {@link Game} model
+ */
public void setUsername(String username) {
this.username = username;
}
+ /**
+ * Updates the game model stored in this view.
+ * Should be called whenever the game state changes so that the next
+ * render reflects the latest state.
+ *
+ * @param model the new {@link Game} model; must not be {@code null}
+ */
@Override
public void update(Game model) {
this.model = model;
}
- // ── punto di ingresso ───────────────────────────────────────
- public void render()
- {
+ /**
+ * Default render entry point, as required by {@link IView}.
+ * Delegates to {@link #renderBoard()}.
+ */
+ @Override
+ public void render() {
renderBoard();
}
- public void fullRender()
- {
- try{
- String os = System.getProperty("os.name").toLowerCase();
- ProcessBuilder pb;
- if (os.contains("win")) {
- pb = new ProcessBuilder("cmd", "/c", "cls");
- } else {
- pb = new ProcessBuilder("clear");
- }
- pb.inheritIO().start().waitFor();
- }
- catch(Exception e){
- }
- ListLayout: + *
The terminal is cleared before rendering.
+ */
+ public void fullRender() {
+ clearTerminal();
+ List Layout:
+ * The terminal is cleared before rendering.
+ */
+ public void renderBoard() {
+ clearTerminal();
+ List Layout:
+ * The terminal is cleared before rendering.
+ */
+ public void renderPlayer() {
+ clearTerminal();
+ List The left column lists game action commands (slot choice, draw, pick…),
+ * the right column lists render shortcuts (full, board, players).
+ *
+ * @return the rendered menu table as a multi-line string
+ */
+ private String printMenuOptions() {
+ var table = new AsciiTable(BorderStyle.ROUNDED, 2);
+ table.addHeader("Menu Options", "Render Options");
+ table.addRow(List.of("0-SlotChoice(pos)", "A-Full Render"));
+ table.addRow(List.of("1-DrawUpperTribe(pos)", "B-Board Render"));
+ table.addRow(List.of("2-DrawUpperBuilding(pos)", "C-Players Render"));
+ table.addRow(List.of("3-DrawLowerTribe(pos)", ""));
+ table.addRow(List.of("4-DrawLowerBuilding(pos)", ""));
+ table.addRow(List.of("5-PickOptionalTribe(pos)", ""));
+ table.addRow(List.of("6-PickOptionalBuilding(pos)", ""));
+ table.addRow(List.of("7-NoOptional", ""));
+ table.addRow(List.of("8-NoUpperCard", ""));
+ table.addRow(List.of("9-NoLowerCard", ""));
return table.build();
}
-}
+ /**
+ * Clears the terminal using a platform-aware system call.
+ * Uses {@code cls} on Windows and {@code clear} on Unix-like systems.
+ * Failures are silently ignored to avoid interrupting the render flow.
+ */
+ private void clearTerminal() {
+ try {
+ String os = System.getProperty("os.name").toLowerCase();
+ ProcessBuilder pb = os.contains("win")
+ ? new ProcessBuilder("cmd", "/c", "cls")
+ : new ProcessBuilder("clear");
+ pb.inheritIO().start().waitFor();
+ } catch (Exception ignored) {}
+ }
+}
\ No newline at end of file
+ *
+ *
+ *
+ *
+ *
+ *