Fix: potential windows solution for TUI
This commit is contained in:
@@ -68,6 +68,11 @@
|
||||
<artifactId>jline-builtins</artifactId>
|
||||
<version>3.26.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jline</groupId>
|
||||
<artifactId>jline-terminal-jansi</artifactId>
|
||||
<version>3.26.3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -15,6 +15,8 @@ import org.jline.terminal.Terminal;
|
||||
import org.jline.terminal.TerminalBuilder;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.jline.builtins.Completers.TreeCompleter.node;
|
||||
|
||||
@@ -35,7 +37,12 @@ public class ClientLauncherTUI {
|
||||
*/
|
||||
public void main() throws InterruptedException {
|
||||
try {
|
||||
terminal = TerminalBuilder.builder().system(true).build();
|
||||
System.setOut(new PrintStream(System.out, true, StandardCharsets.UTF_8));
|
||||
System.setErr(new PrintStream(System.err, true, StandardCharsets.UTF_8));
|
||||
terminal = TerminalBuilder.builder()
|
||||
.system(true)
|
||||
.encoding(StandardCharsets.UTF_8)
|
||||
.build();
|
||||
} catch (IOException e) {
|
||||
System.err.println("Could not initialise terminal: " + e.getMessage());
|
||||
return;
|
||||
@@ -149,6 +156,7 @@ public class ClientLauncherTUI {
|
||||
node("totem"),
|
||||
node("skip"),
|
||||
node("render"),
|
||||
node("help"),
|
||||
node("rematch"),
|
||||
node("quit")
|
||||
);
|
||||
@@ -180,6 +188,7 @@ public class ClientLauncherTUI {
|
||||
}
|
||||
case "skip" -> controller.skipTurn();
|
||||
case "render" -> handleRender(parts);
|
||||
case "help" -> view.renderHelp();
|
||||
case "rematch" -> {
|
||||
if (controller.miniModel == null
|
||||
|| !controller.miniModel.currentState.getGameStage().equals(GameStages.ENDED)) {
|
||||
|
||||
@@ -274,6 +274,6 @@ public class BuildingCard extends PlayableCard implements Cloneable , BuildingEf
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return ":" + " ID:" + String.valueOf(getEffectId())+ " 🍗:"+String.valueOf(getPrice())+" \uD83C\uDFC5:"+String.valueOf(getPrestigeValue());
|
||||
return ":" + " ID:" + String.valueOf(getEffectId())+ " \uD83C\uDF56:"+String.valueOf(getPrice())+" \uD83C\uDFC5:"+String.valueOf(getPrestigeValue());
|
||||
}
|
||||
}
|
||||
@@ -93,7 +93,7 @@ public class Inventor extends Character {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " I_ID:" + String.valueOf(icon);
|
||||
return super.toString() + "ID:" + String.valueOf(icon);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -86,7 +86,7 @@ public class Shaman extends Character {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + " " + "🌟".repeat(icon);
|
||||
return super.toString() + "🌟:" + icon;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,7 +102,7 @@ public class Shaman extends Character {
|
||||
*/
|
||||
@Override
|
||||
public String toStringBoard() {
|
||||
return super.toStringBoard() + " " + "🌟".repeat(icon);
|
||||
return super.toStringBoard() + "🌟:" + icon;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -89,7 +89,7 @@ public abstract class EventCard extends TribeCard {
|
||||
*/
|
||||
@Override
|
||||
public String toStringBoard() {
|
||||
return super.toString() + " " + type.toString();
|
||||
return super.toStringBoard() + " " + type.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -96,7 +96,7 @@ public class Hunt extends EventCard {
|
||||
*/
|
||||
@Override
|
||||
public String toStringBoard() {
|
||||
return super.toStringBoard()+" 1F+"+prestigeMultiplier+"PP"+" X N Hunter";
|
||||
return super.toStringBoard()+" 1\uD83C\uDF56+"+prestigeMultiplier+"\uD83C\uDFC5"+" X N Hunter";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -201,11 +201,9 @@ public class CurrentState implements Serializable {
|
||||
}
|
||||
@Override
|
||||
public String toString(){
|
||||
var table= new AsciiTable(BorderStyle.ROUNDED,6);
|
||||
var table= new AsciiTable(BorderStyle.ROUNDED,4);
|
||||
List<String>header= new ArrayList<>();
|
||||
header.add("Player");
|
||||
header.add("NUpper");
|
||||
header.add("NLower");
|
||||
header.add("Round");
|
||||
header.add("Era");
|
||||
header.add("GameStage");
|
||||
@@ -213,8 +211,6 @@ public class CurrentState implements Serializable {
|
||||
table.addSeparator();
|
||||
List<String>values= new ArrayList<>();
|
||||
values.add(player.getUserName());
|
||||
values.add(Integer.toString(NUpper));
|
||||
values.add(Integer.toString(NLower));
|
||||
values.add(Integer.toString(round));
|
||||
values.add(Integer.toString(Era));
|
||||
values.add(GameStage.toString());
|
||||
|
||||
@@ -74,7 +74,7 @@ public class Order2 extends OrderLogicCard {
|
||||
if(playerList.get(i).played)
|
||||
stringUp.add("");
|
||||
else
|
||||
stringUp.add(i+". "+playerList.get(i).player.getUserName());
|
||||
stringUp.add(playerList.get(i).player.getUserName());
|
||||
}
|
||||
catch (IndexOutOfBoundsException e) {
|
||||
stringUp.add("");
|
||||
@@ -83,9 +83,9 @@ public class Order2 extends OrderLogicCard {
|
||||
table.addRow(stringUp);
|
||||
|
||||
List<String> stringList=new ArrayList<>();
|
||||
stringList.add("+1🍗");
|
||||
stringList.add("-1🍗 / -2\uD83C\uDFC5");
|
||||
stringList.add("+1\uD83C\uDF56");
|
||||
stringList.add("-1\uD83C\uDF56/-2\uD83C\uDFC5");
|
||||
table.addRow(stringList);
|
||||
return "TURN ORDER\n" + table.build() + "\n";
|
||||
return table.build() + "\n";
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ public class Order3 extends OrderLogicCard {
|
||||
if(playerList.get(i).played)
|
||||
stringUp.add("");
|
||||
else
|
||||
stringUp.add(i+". "+playerList.get(i).player.getUserName());
|
||||
stringUp.add(playerList.get(i).player.getUserName());
|
||||
}
|
||||
catch (IndexOutOfBoundsException e) {
|
||||
stringUp.add("");
|
||||
@@ -87,12 +87,12 @@ public class Order3 extends OrderLogicCard {
|
||||
|
||||
List<String> stringList=new ArrayList<>();
|
||||
|
||||
stringList.add("+2 🍗");
|
||||
stringList.add("+2\uD83C\uDF56");
|
||||
stringList.add("--");
|
||||
stringList.add("-1 🍗 / -2 ⭐");
|
||||
stringList.add("-1\uD83C\uDF56/-2\uD83C\uDFC5");
|
||||
table.addRow(stringList);
|
||||
|
||||
|
||||
return "TURN ORDER\n" + table.build() + "\n";
|
||||
return table.build() + "\n";
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ public class Order4 extends OrderLogicCard {
|
||||
if(playerList.get(i).played)
|
||||
stringUp.add("");
|
||||
else
|
||||
stringUp.add(i+". "+playerList.get(i).player.getUserName());
|
||||
stringUp.add(playerList.get(i).player.getUserName());
|
||||
}
|
||||
catch (IndexOutOfBoundsException e) {
|
||||
stringUp.add("");
|
||||
@@ -92,11 +92,11 @@ public class Order4 extends OrderLogicCard {
|
||||
table.addRow(stringUp);
|
||||
|
||||
List<String> stringList=new ArrayList<>();
|
||||
stringList.add("+2 🍗");
|
||||
stringList.add("+1 🍗");
|
||||
stringList.add("+2\uD83C\uDF56");
|
||||
stringList.add("+1\uD83C\uDF56");
|
||||
stringList.add("--");
|
||||
stringList.add("-1 🍗 / -2 ⭐");
|
||||
stringList.add("-1\uD83C\uDF56/-2\uD83C\uDFC5");
|
||||
table.addRow(stringList);
|
||||
return "TURN ORDER\n" + table.build() + "\n";
|
||||
return table.build() + "\n";
|
||||
}
|
||||
}
|
||||
@@ -84,7 +84,7 @@ public class Order5 extends OrderLogicCard {
|
||||
if(playerList.get(i).played)
|
||||
stringUp.add("");
|
||||
else
|
||||
stringUp.add(i+". "+playerList.get(i).player.getUserName());
|
||||
stringUp.add(playerList.get(i).player.getUserName());
|
||||
}
|
||||
catch (IndexOutOfBoundsException e) {
|
||||
stringUp.add("");
|
||||
@@ -93,12 +93,12 @@ public class Order5 extends OrderLogicCard {
|
||||
table.addRow(stringUp);
|
||||
|
||||
List<String> stringList=new ArrayList<>();
|
||||
stringList.add("+3 🍗");
|
||||
stringList.add("+1 🍗");
|
||||
stringList.add("+3\uD83C\uDF56");
|
||||
stringList.add("+1\uD83C\uDF56");
|
||||
stringList.add("--");
|
||||
stringList.add("--");
|
||||
stringList.add("-1 🍗 / -2 ⭐");
|
||||
stringList.add("-1\uD83C\uDF56/-2\uD83C\uDFC5");
|
||||
table.addRow(stringList);
|
||||
return "TURN ORDER\n" + table.build() + "\n";
|
||||
return table.build() + "\n";
|
||||
}
|
||||
}
|
||||
@@ -74,7 +74,7 @@ public abstract class PlayableCard implements Serializable {
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return ":";
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -273,13 +273,8 @@ public class Player implements Serializable {
|
||||
|
||||
var table = new AsciiTable(ROUNDED, 1);
|
||||
|
||||
table.addHeader(this.getUserName());
|
||||
table.addRow("RESOURCES:");
|
||||
if(this.totem != null) {
|
||||
table.addRow("Totem: " + this.totem.toString());
|
||||
}
|
||||
table.addRow("🍗 " + this.getFoodValue());
|
||||
table.addRow("2\uD83C\uDFC5 " + this.getPrestigeValue());
|
||||
String totemStr = (this.totem != null) ? " (" + this.totem.toString() + ")" : "";
|
||||
table.addHeader(this.getUserName() + totemStr + " | \uD83C\uDF56:" + this.getFoodValue() + " | \uD83C\uDFC5:" + this.getPrestigeValue() + " ");
|
||||
table.addSeparator();
|
||||
|
||||
if(!this.hunters.isEmpty()){
|
||||
|
||||
@@ -182,7 +182,7 @@ public class Slot implements Serializable {
|
||||
s.append("↓");
|
||||
}
|
||||
if(getFood()!=0)
|
||||
s.append("+"+getFood()+" 🍗");
|
||||
s.append("+"+getFood()+" \uD83C\uDF56");
|
||||
return s.toString();
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.*;
|
||||
* <p>Example usage:
|
||||
* <pre>{@code
|
||||
* AsciiTable table = new AsciiTable(BorderStyle.UNICODE, 3);
|
||||
* table.addHeader("Name", "🍗", "⭐");
|
||||
* table.addHeader("Name", "🍖", "⭐");
|
||||
* table.addRow("Alice", "4", "12");
|
||||
* table.addRow("Bob", "2", "8");
|
||||
* System.out.println(table.build());
|
||||
@@ -122,7 +122,7 @@ public class AsciiTable {
|
||||
/**
|
||||
* Returns {@code true} when {@code cp} is a wide (2-column) character.
|
||||
* Covers CJK blocks, Hangul, full-width forms, and emoji (including
|
||||
* the specific emoji used in this project: 🍗 U+1F357, ⭐ U+2B50).
|
||||
* the specific emoji used in this project: 🍖 U+1F357, ⭐ U+2B50).
|
||||
*/
|
||||
private static boolean isWide(int cp) {
|
||||
if (cp < 0x1100) return false;
|
||||
@@ -151,7 +151,7 @@ public class AsciiTable {
|
||||
if (cp <= 0xFFE6) return true; // Fullwidth Signs
|
||||
if (cp < 0x1F004) return false;
|
||||
if (cp <= 0x1FAFF) return true; // Emoji (mahjong, playing cards, flags,
|
||||
// misc symbols, transport, 🍗 U+1F357, ...)
|
||||
// misc symbols, transport, 🍖 U+1F357, ...)
|
||||
if (cp < 0x20000) return false;
|
||||
return cp <= 0x3FFFD; // CJK Extension B through G
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.jline.reader.LineReader;
|
||||
import org.jline.terminal.Terminal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -143,8 +142,8 @@ public class TUI implements IView {
|
||||
*/
|
||||
private String buildBoardContent() {
|
||||
List<String> left = List.of(BoardStamp().split("\n"));
|
||||
List<String> right = List.of(printMenuOptions().split("\n"));
|
||||
return AsciiTable.sideBySide(left, right, 3) + "\n" + buildAllHandsContent();
|
||||
List<String> right = List.of(buildAllHandsContent().split("\n"));
|
||||
return AsciiTable.sideBySide(left, right, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,35 +153,9 @@ public class TUI implements IView {
|
||||
private String buildAllHandsContent() {
|
||||
List<Player> players = new ArrayList<>(model.players.values());
|
||||
if (players.isEmpty()) return "";
|
||||
|
||||
int termWidth = (terminal != null && terminal.getWidth() > 0) ? terminal.getWidth() : 80;
|
||||
int gap = 3;
|
||||
|
||||
List<List<String>> panels = new ArrayList<>();
|
||||
List<Integer> panelWidths = new ArrayList<>();
|
||||
for (Player p : players) {
|
||||
List<String> lines = Arrays.asList(p.toString().split("\n"));
|
||||
panels.add(lines);
|
||||
panelWidths.add(lines.stream().mapToInt(l -> visibleLength(l)).max().orElse(0));
|
||||
}
|
||||
|
||||
StringBuilder result = new StringBuilder();
|
||||
int i = 0;
|
||||
while (i < panels.size()) {
|
||||
int rowWidth = panelWidths.get(i);
|
||||
int j = i + 1;
|
||||
while (j < panels.size()
|
||||
&& rowWidth + gap + panelWidths.get(j) <= termWidth) {
|
||||
rowWidth += gap + panelWidths.get(j);
|
||||
j++;
|
||||
}
|
||||
List<String> merged = panels.get(i);
|
||||
for (int k = i + 1; k < j; k++) {
|
||||
merged = Arrays.asList(
|
||||
AsciiTable.sideBySide(merged, panels.get(k), gap).split("\n"));
|
||||
}
|
||||
result.append(String.join("\n", merged)).append("\n");
|
||||
i = j;
|
||||
for (Player p : players) {
|
||||
result.append(p.toString()).append("\n");
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
@@ -317,62 +290,58 @@ public class TUI implements IView {
|
||||
slotPlayers.add(entry.getValue() != null ? entry.getValue().getUserName() : " ");
|
||||
}
|
||||
|
||||
var TribeUpper = new AsciiTable(BorderStyle.ROUNDED, 1);
|
||||
var TribeLower = new AsciiTable(BorderStyle.ROUNDED, 1);
|
||||
var BuildUpper = new AsciiTable(BorderStyle.ROUNDED, 1);
|
||||
BuildUpper.addHeader("Building ");
|
||||
var BuildLower = new AsciiTable(BorderStyle.ROUNDED, 1);
|
||||
BuildLower.addHeader("Building ");
|
||||
var UpperCards = new AsciiTable(BorderStyle.ROUNDED, 2);
|
||||
var LowerCards = new AsciiTable(BorderStyle.ROUNDED, 2);
|
||||
UpperCards.addHeader("Char/Events", "Building");
|
||||
LowerCards.addHeader("Char/Events", "Building");
|
||||
|
||||
List<String> upperTribeRows = new ArrayList<>();
|
||||
List<String> lowerTribeRows = new ArrayList<>();
|
||||
upperTribeRows.add("Char/Events");
|
||||
lowerTribeRows.add("Char/Events");
|
||||
|
||||
int max = Math.max(model.upperListTribeCards.size(), model.lowerListTribeCards.size());
|
||||
for (int i = 0; i < max; i++) {
|
||||
if (i < model.upperListTribeCards.size())
|
||||
upperTribeRows.add(i + model.upperListTribeCards.get(i).toStringBoard());
|
||||
if (i < model.lowerListTribeCards.size())
|
||||
lowerTribeRows.add(i + "" + model.lowerListTribeCards.get(i).toStringBoard());
|
||||
int maxU = Math.max(model.upperListTribeCards.size(), model.upperListBuildingCards.size());
|
||||
for (int i = 0; i < maxU; i++) {
|
||||
String t = i < model.upperListTribeCards.size() ? i + model.upperListTribeCards.get(i).toStringBoard() : "";
|
||||
String b = i < model.upperListBuildingCards.size() ? i + model.upperListBuildingCards.get(i).toString() : "";
|
||||
UpperCards.addRow(t, b);
|
||||
}
|
||||
|
||||
int maxB = Math.max(model.upperListBuildingCards.size(), model.lowerListBuildingCards.size());
|
||||
for (int i = 0; i < maxB; i++) {
|
||||
if (i < model.upperListBuildingCards.size())
|
||||
BuildUpper.addRow(i + model.upperListBuildingCards.get(i).toString());
|
||||
if (i < model.lowerListBuildingCards.size())
|
||||
BuildLower.addRow(i + model.lowerListBuildingCards.get(i).toString());
|
||||
int maxL = Math.max(model.lowerListTribeCards.size(), model.lowerListBuildingCards.size());
|
||||
for (int i = 0; i < maxL; i++) {
|
||||
String t = i < model.lowerListTribeCards.size() ? i + model.lowerListTribeCards.get(i).toStringBoard() : "";
|
||||
String b = i < model.lowerListBuildingCards.size() ? i + model.lowerListBuildingCards.get(i).toString() : "";
|
||||
LowerCards.addRow(t, b);
|
||||
}
|
||||
|
||||
upperTribeRows.forEach(TribeUpper::addRow);
|
||||
lowerTribeRows.forEach(TribeLower::addRow);
|
||||
offerTrack.addRow(slotPlayers);
|
||||
offerTrack.addRow(slotNames);
|
||||
|
||||
return "CURRENT STATE\n" + model.currentState + "\n" + model.orderLogicCard + "\n"
|
||||
+ AsciiTable.sideBySide(
|
||||
Arrays.stream(TribeUpper.build().split("\n")).toList(),
|
||||
Arrays.stream(BuildUpper.build().split("\n")).toList(), 2)
|
||||
+ "\n" + offerTrack.build() + "\n"
|
||||
+ AsciiTable.sideBySide(
|
||||
List.of(TribeLower.build().split("\n")),
|
||||
Arrays.stream(BuildLower.build().split("\n")).toList(), 2);
|
||||
String upperSection = UpperCards.build();
|
||||
|
||||
String middleSection = AsciiTable.sideBySide(
|
||||
List.of(model.orderLogicCard.toString().split("\n")),
|
||||
List.of(offerTrack.build().split("\n")), 3);
|
||||
|
||||
String lowerSection = LowerCards.build();
|
||||
|
||||
return model.currentState + "\n"
|
||||
+ upperSection + "\n"
|
||||
+ middleSection + "\n"
|
||||
+ lowerSection;
|
||||
}
|
||||
|
||||
// ── Menu options ──────────────────────────────────────────────────────────
|
||||
// ── Help ──────────────────────────────────────────────────────────────────
|
||||
|
||||
private String printMenuOptions() {
|
||||
/** Displays the command help panel. */
|
||||
public void renderHelp() {
|
||||
display(buildHelpContent());
|
||||
}
|
||||
|
||||
private String buildHelpContent() {
|
||||
var table = new AsciiTable(BorderStyle.ROUNDED, 1);
|
||||
table.addHeader("Commands");
|
||||
table.addRow("slot <pos>");
|
||||
table.addRow("draw upper tribe <pos>");
|
||||
table.addRow("draw upper building <pos>");
|
||||
table.addRow("draw lower tribe <pos>");
|
||||
table.addRow("draw lower building <pos>");
|
||||
table.addRow("draw upper|lower tribe|building <pos>");
|
||||
table.addRow("totem <pos>");
|
||||
table.addRow("skip");
|
||||
table.addRow("render");
|
||||
table.addRow("help");
|
||||
table.addRow("rematch | quit");
|
||||
return table.build();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user