Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: maherg/tictactoe
base: 1522cf9072
...
head fork: maherg/tictactoe
compare: fe92187cc2
Checking mergeability… Don't worry, you can still create the pull request.
  • 5 commits
  • 20 files changed
  • 0 commit comments
  • 1 contributor
Showing with 283 additions and 38 deletions.
  1. +12 −3 README.txt
  2. +18 −0 issues/issue-04642f70b0da9600bca037dfef53e49f5c884d2b.yaml
  3. +18 −0 issues/issue-13b051f7dfa90c6776a58c911350d3074b510ae6.yaml
  4. +18 −0 issues/issue-5ed5279f271fb029ddbd6980456acc32fb1c3442.yaml
  5. +18 −0 issues/issue-65466e8a8b6707202ebb8bd15091cfe3ca96c5f9.yaml
  6. +5 −0 pom.xml
  7. +36 −11 src/main/java/tictactoe/boards/planar/PlanarBoard.java
  8. +8 −10 src/main/java/tictactoe/gameplay/AbstractGame.java
  9. +3 −1 src/main/java/tictactoe/gameplay/modes/ExitMode.java
  10. +29 −6 src/main/java/tictactoe/gameplay/modes/traditional/AbstractTraditionalMode.java
  11. +5 −0 src/main/java/tictactoe/players/AbstractPlayer.java
  12. +2 −1  src/main/java/tictactoe/players/ai/ArtificialPlayer.java
  13. +2 −1  src/main/java/tictactoe/players/human/LocalHumanPlayer.java
  14. +2 −0  src/main/java/tictactoe/ui/Inquiry.java
  15. +6 −0 src/main/java/tictactoe/ui/Menu.java
  16. +2 −0  src/main/java/tictactoe/ui/OutputText.java
  17. +12 −0 src/main/java/tictactoe/ui/TextColor.java
  18. +9 −1 src/main/java/tictactoe/ui/console/ConsoleInquiry.java
  19. +22 −2 src/main/java/tictactoe/ui/console/ConsoleMenu.java
  20. +56 −2 src/main/java/tictactoe/ui/console/ConsoleOutputText.java
View
15 README.txt
@@ -6,9 +6,18 @@ This is a Java implementation of a Tic-Tac-Toe game to be played through the con
Features
--------
-1. Several gameplay modes such as human vs human, human vs computer, computer vs computer.
-2. Possible to have different sizes of boards (this needs to be thoroughly tested).
-3. Possible to implement further interfaces for it instead of just a console-based one.
+* Several gameplay modes such as human vs human, human vs computer, computer vs computer.
+* Possible to have different sizes of boards (this needs to be thoroughly tested).
+* Possible to implement further interfaces for it instead of just a console-based one.
+* Console interface features bash coloring to aid readability.
+
+Artificial Intelligence
+-----------------------
+
+I have based the implementation mainly on the minimax algorithm except that the score
+for each node is set from the perspective of the player (instead of maximizer, minimizer).
+
+It's the analysis function that needs to further improved to properly weigh the nodes properly.
Installation
------------
View
18 issues/issue-04642f70b0da9600bca037dfef53e49f5c884d2b.yaml
@@ -0,0 +1,18 @@
+--- !ditz.rubyforge.org,2008-03-06/issue
+title: Extend the console coloring detection to see if the shell allows it as well
+desc: ""
+type: :feature
+component: user-interface
+release: "1.1"
+reporter: Maher Gamal <mahergamal@gmail.com>
+status: :unstarted
+disposition:
+creation_time: 2012-02-23 20:17:36.193458 Z
+references: []
+
+id: 04642f70b0da9600bca037dfef53e49f5c884d2b
+log_events:
+- - 2012-02-23 20:17:36.721355 Z
+ - Maher Gamal <mahergamal@gmail.com>
+ - created
+ - ""
View
18 issues/issue-13b051f7dfa90c6776a58c911350d3074b510ae6.yaml
@@ -0,0 +1,18 @@
+--- !ditz.rubyforge.org,2008-03-06/issue
+title: Improve the performance of the game tree generation by avoiding unneeded sub-trees
+desc: ""
+type: :task
+component: players
+release: "1.1"
+reporter: Maher Gamal <mahergamal@gmail.com>
+status: :unstarted
+disposition:
+creation_time: 2012-02-23 19:27:52.282768 Z
+references: []
+
+id: 13b051f7dfa90c6776a58c911350d3074b510ae6
+log_events:
+- - 2012-02-23 19:27:52.946412 Z
+ - Maher Gamal <mahergamal@gmail.com>
+ - created
+ - ""
View
18 issues/issue-5ed5279f271fb029ddbd6980456acc32fb1c3442.yaml
@@ -0,0 +1,18 @@
+--- !ditz.rubyforge.org,2008-03-06/issue
+title: Incorporate the jansi library to colorize the console interface for Windows
+desc: ""
+type: :feature
+component: user-interface
+release: "1.1"
+reporter: Maher Gamal <mahergamal@gmail.com>
+status: :unstarted
+disposition:
+creation_time: 2012-02-23 20:38:33.060812 Z
+references: []
+
+id: 5ed5279f271fb029ddbd6980456acc32fb1c3442
+log_events:
+- - 2012-02-23 20:38:33.628017 Z
+ - Maher Gamal <mahergamal@gmail.com>
+ - created
+ - ""
View
18 issues/issue-65466e8a8b6707202ebb8bd15091cfe3ca96c5f9.yaml
@@ -0,0 +1,18 @@
+--- !ditz.rubyforge.org,2008-03-06/issue
+title: Some output text does not get endLine()'ed correctly
+desc: ""
+type: :bugfix
+component: user-interface
+release: "1.1"
+reporter: Maher Gamal <mahergamal@gmail.com>
+status: :unstarted
+disposition:
+creation_time: 2012-02-23 21:06:59.612782 Z
+references: []
+
+id: 65466e8a8b6707202ebb8bd15091cfe3ca96c5f9
+log_events:
+- - 2012-02-23 21:07:00.156436 Z
+ - Maher Gamal <mahergamal@gmail.com>
+ - created
+ - ""
View
5 pom.xml
@@ -36,5 +36,10 @@
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency>
+ <dependency>
+ <groupId>org.fusesource.jansi</groupId>
+ <artifactId>jansi</artifactId>
+ <version>1.8</version>
+ </dependency>
</dependencies>
</project>
View
47 src/main/java/tictactoe/boards/planar/PlanarBoard.java
@@ -13,6 +13,7 @@
import tictactoe.boards.gametree.BoardGameTree;
import tictactoe.boards.gametree.BoardGameTreeNavigator;
import tictactoe.players.Player;
+import tictactoe.ui.TextColor;
import tictactoe.ui.UiFactory;
public class PlanarBoard implements Board {
@@ -73,7 +74,12 @@ public void redraw() {
uiFactory.createOutputText().endLine().redraw();
for (int rowIndex = 0; rowIndex < height; rowIndex++) {
for (int columnIndex = 0; columnIndex < width; columnIndex++) {
- uiFactory.createOutputText().withIndent(1).withText("[%s]", board[rowIndex][columnIndex]).redraw();
+ TextColor cellColor = TextColor.WHITE;
+ if (!StringUtils.isNumeric(board[rowIndex][columnIndex])) {
+ cellColor = TextColor.YELLOW;
+ }
+ uiFactory.createOutputText().withIndent(1).withText("[%s]", board[rowIndex][columnIndex])
+ .withTextColor(cellColor).redraw();
}
uiFactory.createOutputText().endLine(2).redraw();
}
@@ -137,7 +143,7 @@ public boolean isDiagonalSequenceFound(String symbol, int sequenceSize) {
if (sequenceSize > largestPossibleDiagonalSize) {
return false;
}
-
+ // TODO : Rewrite this block to work on any dimension, it's now written just to check for 3x3.
if ((board[0][0].equals(symbol) && board[1][1].equals(symbol) && board[2][2].equals(symbol))
|| (board[2][0].equals(symbol) && board[1][1].equals(symbol) && board[0][2].equals(symbol))) {
log.debug("Diagonal sequence found for symbol {}", symbol);
@@ -210,13 +216,14 @@ private int heightIndexFor(int coordinate) {
@Override
public int scoreAnalysisFor(Player player) {
- return horizontalAnalysisFor(player) + verticalAnalysisFor(player) + diagonalAnalysisFor(player);
+ return Math.max(Math.max(horizontalAnalysisFor(player), verticalAnalysisFor(player)),
+ diagonalAnalysisFor(player));
}
private int horizontalAnalysisFor(Player player) {
int horizontalScore = 0;
for (int row = 0; row < height; row++) {
- horizontalScore += calculateAnalysisScoreFor(board[row], player);
+ horizontalScore = Math.max(horizontalScore, calculateAnalysisScoreFor(horizontalSlice(row), player));
}
return horizontalScore;
}
@@ -224,23 +231,41 @@ private int horizontalAnalysisFor(Player player) {
private int verticalAnalysisFor(Player player) {
int verticalScore = 0;
for (int column = 0; column < width; column++) {
- verticalScore += calculateAnalysisScoreFor(verticalSlice(column), player);
+ verticalScore = Math.max(verticalScore, calculateAnalysisScoreFor(verticalSlice(column), player));
}
return verticalScore;
}
private int diagonalAnalysisFor(Player player) {
// FIXME : Make the diagonal analysis work on all possible diagonals in rectangular dimensions as well.
- int diagonalScore = 0;
- diagonalScore += calculateAnalysisScoreFor(new String[] { board[0][0], board[1][1], board[2][2] }, player);
- diagonalScore += calculateAnalysisScoreFor(new String[] { board[0][2], board[1][1], board[2][0] }, player);
- return diagonalScore;
+ int diagonal_1 = calculateAnalysisScoreFor(new String[] { board[0][0], board[1][1], board[2][2] }, player);
+ int diagonal_2 = calculateAnalysisScoreFor(new String[] { board[0][2], board[1][1], board[2][0] }, player);
+ return Math.max(diagonal_1, diagonal_2);
}
private int calculateAnalysisScoreFor(String[] slice, Player player) {
+ int score = 0;
String sliceString = StringUtils.join(slice);
- int occurances = StringUtils.countMatches(sliceString, player.getSymbol());
- return occurances * ANALYSIS_FACTOR;
+ String opponentMoves = sliceString.replaceAll("[0-9" + player.getSymbol() + "]", "");
+ int opponentLength = opponentMoves.length();
+ int playerLength = StringUtils.countMatches(sliceString, player.getSymbol());
+ if (playerLength == 2) {
+ return 300;
+ }
+ if (playerLength == 1) {
+ return 200;
+ }
+ if (opponentLength == 1) {
+ return -50;
+ }
+ if (opponentLength == 2) {
+ return -100;
+ }
+ return score;
+ }
+
+ private String[] horizontalSlice(int rowIndex) {
+ return board[rowIndex];
}
private String[] verticalSlice(int columnIndex) {
View
18 src/main/java/tictactoe/gameplay/AbstractGame.java
@@ -10,6 +10,7 @@
import tictactoe.gameplay.modes.traditional.TraditionalSpectatorMode;
import tictactoe.ui.Menu;
import tictactoe.ui.MenuItem;
+import tictactoe.ui.TextColor;
import tictactoe.ui.UiFactory;
public abstract class AbstractGame implements Game {
@@ -36,7 +37,6 @@ public void changeStageTo(Stage stage) {
@Override
public void mainLoop() {
while (true) {
- uiFactory.createClearScreen().redraw();
showTopHeader();
switch (stage) {
case MODE_SELECTION:
@@ -50,30 +50,28 @@ public void mainLoop() {
case COMPLETED:
changeStageTo(Stage.MODE_SELECTION);
break;
- case EXITING:
- showExitingMessage();
- return;
}
}
}
private void showTopHeader() {
- uiFactory.createOutputText().withText("Tic-Tac-Toe (written by Maher Gamal)\n\n").redraw();
- }
-
- private void showExitingMessage() {
- uiFactory.createOutputText().withText("Exiting game !").redraw();
+ uiFactory.createClearScreen().redraw();
+ uiFactory.createOutputText().withText("Tic-Tac-Toe (written by Maher Gamal)\n\n")
+ .withTextColor(TextColor.LIGHT_CYAN).redraw();
}
private void askForGamePlayMode() {
Menu selectionMenu = uiFactory
.createMenu()
.withTitle("Gameplay Modes")
+ .withTitleColor(TextColor.LIGHT_GREEN)
+ .withItemsColor(TextColor.YELLOW)
.withItems(
new MenuItem[] { new TraditionalSinglePlayerMode(uiFactory),
new TraditionalMultiPlayerMode(uiFactory), new TraditionalSpectatorMode(uiFactory),
- new ExitMode(uiFactory) }).withQuestion("Please select a gameplay mode");
+ new ExitMode(uiFactory) }).withQuestion("Please select a gameplay mode")
+ .withQuestionColor(TextColor.LIGHT_PURPLE);
selectionMenu.redraw();
changeModeTo((Mode) selectionMenu.selectedItem());
}
View
4 src/main/java/tictactoe/gameplay/modes/ExitMode.java
@@ -1,6 +1,7 @@
package tictactoe.gameplay.modes;
import tictactoe.ui.MenuItem;
+import tictactoe.ui.TextColor;
import tictactoe.ui.UiFactory;
public class ExitMode implements Mode, MenuItem {
@@ -13,7 +14,8 @@ public ExitMode(UiFactory uiFactory) {
@Override
public void playLoop() {
- uiFactory.createOutputText().withText("Exiting game ...").endLine().redraw();
+ uiFactory.createOutputText().withText("Exiting game ...").withTextColor(TextColor.LIGHT_GREEN).endLine()
+ .redraw();
// FIXME : Exiting the game should happen from AbstractGame or it's subclasses, not from a mode.
System.exit(0);
}
View
35 src/main/java/tictactoe/gameplay/modes/traditional/AbstractTraditionalMode.java
@@ -3,6 +3,8 @@
import java.util.ArrayList;
import java.util.List;
+import org.apache.commons.lang3.StringUtils;
+
import tictactoe.boards.Board;
import tictactoe.boards.InvalidBoardMoveException;
import tictactoe.boards.planar.PlanarBoard;
@@ -10,6 +12,7 @@
import tictactoe.players.Player;
import tictactoe.players.PlayerFactory;
import tictactoe.ui.MenuItem;
+import tictactoe.ui.TextColor;
import tictactoe.ui.UiFactory;
public abstract class AbstractTraditionalMode implements Mode, MenuItem {
@@ -23,6 +26,8 @@
private UiFactory uiFactory;
protected PlayerFactory playerFactory;
private List<Player> players = new ArrayList<Player>();
+ private String modeHeaderText;
+ private long startTime;
public AbstractTraditionalMode(UiFactory uiFactory, String name) {
this.uiFactory = uiFactory;
@@ -33,17 +38,19 @@ public AbstractTraditionalMode(UiFactory uiFactory, String name) {
@Override
public void playLoop() {
+ startTime = System.currentTimeMillis();
buildNecessaryAI();
+ buildModeHeaderText();
while (!isGameOver()) {
for (Player player : players) {
- uiFactory.createClearScreen().redraw();
- board.redraw();
+ redrawModeScreen();
while (true) {
try {
player.playMove();
break;
} catch (InvalidBoardMoveException e) {
- uiFactory.createOutputText().withText(e.getMessage()).endLine().redraw();
+ uiFactory.createOutputText().withText(e.getMessage()).withTextColor(TextColor.LIGHT_RED)
+ .endLine().redraw();
}
}
if (isGameOverByThisPlayer(player)) {
@@ -54,6 +61,20 @@ public void playLoop() {
}
}
+ private void buildModeHeaderText() {
+ String[] elements = new String[] { "Tic-Tac-Toe", StringUtils.join(players, " VS "),
+ String.format("Board %dx%d", BOARD_HEIGHT, BOARD_WIDTH),
+ String.format("Time elapsed is %d", (System.currentTimeMillis() - startTime) / 1000), };
+ modeHeaderText = StringUtils.join(elements, " | ");
+ }
+
+ private void redrawModeScreen() {
+ uiFactory.createClearScreen().redraw();
+ uiFactory.createOutputText().withText(modeHeaderText.toString()).withTextColor(TextColor.LIGHT_BLUE).endLine(2)
+ .redraw();
+ board.redraw();
+ }
+
public boolean isGameOverByThisPlayer(Player player) {
String symbol = player.getSymbol();
if (board.isHorizontalSequenceFound(symbol, WINNING_SEQUENCE_SIZE)
@@ -62,11 +83,12 @@ public boolean isGameOverByThisPlayer(Player player) {
uiFactory
.createInquiry()
.withQuestion("Game over, player %s has WON the game ! (press any key to return to menu)",
- player.getName()).redraw();
+ player.getName()).withQuestionColor(TextColor.LIGHT_GREEN).redraw();
return true;
} else if (!board.hasAvailableMoves()) {
uiFactory.createInquiry()
- .withQuestion("Game over, players ended with a DRAW ! (press any key to return to menu)").redraw();
+ .withQuestion("Game over, players ended with a DRAW ! (press any key to return to menu)")
+ .withQuestionColor(TextColor.LIGHT_RED).redraw();
return true;
} else {
return false;
@@ -87,7 +109,8 @@ public boolean isGameOver() {
}
private void buildNecessaryAI() {
- uiFactory.createOutputText().withText("Building the AI for the game, please wait ...").endLine().redraw();
+ uiFactory.createOutputText().withText("Building the AI for the game, please wait ...")
+ .withTextColor(TextColor.LIGHT_CYAN).endLine().redraw();
for (Player player : players) {
if (player.requiresGameTreeNavigator()) {
player.setGameTreeNavigator(board.buildGameTreeNavigatorFor(players));
View
5 src/main/java/tictactoe/players/AbstractPlayer.java
@@ -50,4 +50,9 @@ public void setBoard(Board board) {
this.board = board;
}
+ @Override
+ public String toString() {
+ return getName();
+ }
+
}
View
3  src/main/java/tictactoe/players/ai/ArtificialPlayer.java
@@ -6,6 +6,7 @@
import tictactoe.boards.InvalidBoardMoveException;
import tictactoe.boards.gametree.BoardGameTreeNode;
import tictactoe.players.AbstractPlayer;
+import tictactoe.ui.TextColor;
public class ArtificialPlayer extends AbstractPlayer {
@@ -43,7 +44,7 @@ private int decideNextMove() {
@SuppressWarnings("static-access")
private void simulateThinkingTime() {
- uiFactory.createOutputText().withText("Player '%s' is thinking ...", getName()).endLine().redraw();
+ uiFactory.createOutputText().withText("Player '%s' is thinking ...", getName()).withTextColor(TextColor.LIGHT_PURPLE).redraw();
try {
Thread.currentThread().sleep(SIMULATED_THINKING_TIME_IN_MSECS);
} catch (InterruptedException e) {
View
3  src/main/java/tictactoe/players/human/LocalHumanPlayer.java
@@ -4,6 +4,7 @@
import tictactoe.boards.InvalidBoardMoveException;
import tictactoe.players.AbstractPlayer;
import tictactoe.ui.Inquiry;
+import tictactoe.ui.TextColor;
public class LocalHumanPlayer extends AbstractPlayer {
@@ -20,7 +21,7 @@ public void playMove() throws InvalidBoardMoveException {
private int promptMeForNextMoveCoordinate() {
Inquiry inquiry = uiFactory.createInquiry().withQuestion("%s, decide your next move", getName())
- .withType(Integer.class);
+ .withQuestionColor(TextColor.LIGHT_PURPLE).withType(Integer.class);
inquiry.redraw();
return inquiry.getResponseAs(Integer.class);
}
View
2  src/main/java/tictactoe/ui/Inquiry.java
@@ -4,6 +4,8 @@
Inquiry withQuestion(String question, Object... args);
+ Inquiry withQuestionColor(TextColor color);
+
Inquiry withType(Class inquiryType);
boolean hasType();
View
6 src/main/java/tictactoe/ui/Menu.java
@@ -4,9 +4,15 @@
Menu withTitle(String title);
+ Menu withTitleColor(TextColor color);
+
Menu withItems(MenuItem... items);
+ Menu withItemsColor(TextColor color);
+
Menu withQuestion(String question);
+ Menu withQuestionColor(TextColor color);
+
MenuItem selectedItem();
}
View
2  src/main/java/tictactoe/ui/OutputText.java
@@ -6,6 +6,8 @@
OutputText withText(String text, Object... args);
+ OutputText withTextColor(TextColor color);
+
OutputText endLine();
OutputText endLine(int recurrence);
View
12 src/main/java/tictactoe/ui/TextColor.java
@@ -0,0 +1,12 @@
+package tictactoe.ui;
+
+public enum TextColor {
+ WHITE,
+ YELLOW,
+ LIGHT_PURPLE,
+ LIGHT_RED,
+ LIGHT_GRAY,
+ LIGHT_BLUE,
+ LIGHT_GREEN,
+ LIGHT_CYAN, ;
+}
View
10 src/main/java/tictactoe/ui/console/ConsoleInquiry.java
@@ -3,6 +3,7 @@
import tictactoe.ui.Inquiry;
import tictactoe.ui.InvalidInquiryResponseException;
import tictactoe.ui.OutputText;
+import tictactoe.ui.TextColor;
public class ConsoleInquiry extends AbstractConsoleDrawable implements Inquiry {
@@ -27,7 +28,8 @@ public void redraw() {
}
break;
} catch (InvalidInquiryResponseException e) {
- uiFactory.createOutputText().withText(e.getMessage()).endLine().redraw();
+ uiFactory.createOutputText().withText(e.getMessage()).withTextColor(TextColor.LIGHT_RED).endLine()
+ .redraw();
}
}
@@ -70,4 +72,10 @@ public boolean hasType() {
return responseType != null;
}
+ @Override
+ public Inquiry withQuestionColor(TextColor color) {
+ this.question.withTextColor(color);
+ return this;
+ }
+
}
View
24 src/main/java/tictactoe/ui/console/ConsoleMenu.java
@@ -4,12 +4,14 @@
import tictactoe.ui.Menu;
import tictactoe.ui.MenuItem;
import tictactoe.ui.OutputText;
+import tictactoe.ui.TextColor;
public class ConsoleMenu extends AbstractConsoleDrawable implements Menu {
private OutputText title;
private Inquiry inquiry;
private Object[] items;
+ private TextColor itemsColor;
private Object selected;
public ConsoleMenu(ConsoleUiFactory uiFactory) {
@@ -21,7 +23,7 @@ public void redraw() {
title.redraw();
for (int i = 0; i < items.length; i++) {
String itemText = String.format("%d. %s", i + 1, items[i]);
- uiFactory.createOutputText().withIndent(1).withText(itemText).endLine().redraw();
+ uiFactory.createOutputText().withIndent(1).withText(itemText).withTextColor(itemsColor).endLine().redraw();
}
while (true) {
uiFactory.createOutputText().endLine(1).redraw();
@@ -32,7 +34,7 @@ public void redraw() {
break;
} catch (IndexOutOfBoundsException e) {
uiFactory.createOutputText().withText("Please select a valid item from %d to %d", 1, items.length)
- .endLine().redraw();
+ .withTextColor(TextColor.LIGHT_RED).endLine().redraw();
}
}
@@ -61,4 +63,22 @@ public Menu withQuestion(String question) {
public MenuItem selectedItem() {
return (MenuItem) selected;
}
+
+ @Override
+ public Menu withTitleColor(TextColor color) {
+ this.title.withTextColor(color);
+ return this;
+ }
+
+ @Override
+ public Menu withItemsColor(TextColor color) {
+ this.itemsColor = color;
+ return this;
+ }
+
+ @Override
+ public Menu withQuestionColor(TextColor color) {
+ this.inquiry.withQuestionColor(color);
+ return this;
+ }
}
View
58 src/main/java/tictactoe/ui/console/ConsoleOutputText.java
@@ -2,12 +2,20 @@
import java.io.PrintStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
import tictactoe.ui.OutputText;
+import tictactoe.ui.TextColor;
public class ConsoleOutputText extends AbstractConsoleDrawable implements OutputText {
+ private Logger log = LoggerFactory.getLogger(getClass());
private PrintStream writer = System.out;
private StringBuffer text = new StringBuffer();
+ private StringBuffer textColorized = new StringBuffer();
+ private TextColor color;
+ private boolean colorable = !System.getProperty("os.name").toLowerCase().contains("windows");
private String newLineCharacter = System.getProperty("line.separator");
public ConsoleOutputText(ConsoleUiFactory uiFactory) {
@@ -22,7 +30,7 @@ public OutputText withText(String text, Object... args) {
@Override
public OutputText endLine() {
- text.append(newLineCharacter);
+ endLine(1);
return this;
}
@@ -44,7 +52,53 @@ public OutputText withIndent(int level) {
@Override
public void redraw() {
- writer.print(text);
+ if (isColorable() && color != null) {
+ colorizeText();
+ writer.print(textColorized.toString());
+ } else {
+ writer.print(text);
+ }
+ }
+
+ @Override
+ public OutputText withTextColor(TextColor color) {
+ this.color = color;
+ return this;
}
+ private void colorizeText() {
+ String prefix = "";
+ String suffix = "\033[m";
+ switch (color) {
+ case WHITE:
+ prefix = "\033[1;37m";
+ break;
+ case YELLOW:
+ prefix = "\033[1;33m";
+ break;
+ case LIGHT_PURPLE:
+ prefix = "\033[1;35m";
+ break;
+ case LIGHT_RED:
+ prefix = "\033[1;31m";
+ break;
+ case LIGHT_BLUE:
+ prefix = "\033[1;34m";
+ break;
+ case LIGHT_GREEN:
+ prefix = "\033[1;32m";
+ break;
+ case LIGHT_GRAY:
+ prefix = "\033[1;37m";
+ break;
+ case LIGHT_CYAN:
+ prefix = "\033[1;36m";
+ break;
+ }
+ textColorized.append(prefix).append(text).append(suffix);
+ }
+
+ public boolean isColorable() {
+ return colorable;
+ }
}

No commit comments for this range

Something went wrong with that request. Please try again.