// TexWriter.java
package net.sf.gogui.tex;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Locale;
import net.sf.gogui.game.ConstNode;
import net.sf.gogui.game.ConstGameTree;
import net.sf.gogui.game.NodeUtil;
import net.sf.gogui.go.ConstBoard;
import net.sf.gogui.go.GoColor;
import static net.sf.gogui.go.GoColor.BLACK;
import static net.sf.gogui.go.GoColor.WHITE;
import static net.sf.gogui.go.GoColor.EMPTY;
import static net.sf.gogui.go.GoColor.BLACK_WHITE;
import net.sf.gogui.go.GoPoint;
import net.sf.gogui.go.Move;
import net.sf.gogui.util.StringUtil;
/** Write a game or board position in PSGO style to a stream. */
public class TexWriter
{
public TexWriter(String title, OutputStream out, ConstBoard board,
String[][] markLabel, boolean[][] mark,
boolean[][] markTriangle, boolean[][] markCircle,
boolean[][] markSquare, boolean[][] markSelect)
{
m_out = new PrintStream(out);
printBeginDocument();
if (! StringUtil.isEmpty(title))
m_out.println("\\section*{" + escape(title) + "}");
printBeginPSGo(board.getSize());
printPosition(board, markLabel, mark, markTriangle, markCircle,
markSquare, markSelect);
printEndPSGo();
m_out.println("\\\\");
m_out.print(board.getToMove().getCapitalizedName());
m_out.println(" to play");
printEndDocument();
m_out.close();
}
public TexWriter(String title, OutputStream out, ConstGameTree tree)
{
m_out = new PrintStream(out);
printBeginDocument();
if (! StringUtil.isEmpty(title))
m_out.println("\\section*{" + escape(title) + "}");
printBeginPSGo(tree.getBoardSize());
String comment = printTree(tree);
printEndPSGo();
if (! comment.equals(""))
{
m_out.println("\\\\");
m_out.println(comment);
}
printEndDocument();
m_out.close();
}
private final PrintStream m_out;
/** Escape LaTeX special characters in text. */
private String escape(String text)
{
text = text.replaceAll("\\#", "\\\\#");
text = text.replaceAll("\\$", "\\\\\\$");
text = text.replaceAll("%", "\\\\%");
text = text.replaceAll("\\&", "\\\\&");
text = text.replaceAll("~", "\\\\~{}");
text = text.replaceAll("_", "\\\\_");
text = text.replaceAll("\\^", "\\\\^{}");
text = text.replaceAll("\\\\", "\\$\\\\backslash\\$");
text = text.replaceAll("\\{", "\\\\{");
text = text.replaceAll("\\}", "\\\\}");
return text;
}
private String getStoneInTextString(int moveNumber, GoColor color)
{
return ("\\stone[" + moveNumber + "]{"
+ (color == BLACK ? "black" : "white") + "}");
}
private void printBeginDocument()
{
m_out.println("\\documentclass{article}");
m_out.println("\\usepackage{psgo} % version 0.14 or newer");
m_out.println("\\pagestyle{empty}");
m_out.println("\\begin{document}");
m_out.println();
}
private void printBeginPSGo(int size)
{
m_out.println("\\begin{psgoboard}[" + size + "]");
}
private void printColor(GoColor color)
{
if (color == BLACK)
m_out.print("{black}");
else
{
assert color == WHITE;
m_out.print("{white}");
}
}
private void printCoordinates(GoPoint point)
{
assert point != null;
String s = point.toString();
m_out.print("{" + s.substring(0, 1).toLowerCase(Locale.ENGLISH) + "}{"
+ s.substring(1) + "}");
}
private void printEndDocument()
{
m_out.println();
m_out.println("\\end{document}");
}
private void printEndPSGo()
{
m_out.println("\\end{psgoboard}");
}
private String printTree(ConstGameTree tree)
{
StringBuilder comment = new StringBuilder();
int size = tree.getBoardSize();
ConstNode firstMoveAtPoint[][] = new ConstNode[size][size];
ArrayList<ConstNode> needsComment = new ArrayList<ConstNode>();
boolean blackToMove = true;
m_out.println("\\setcounter{gomove}{0}");
ConstNode node = tree.getRootConst();
while (node != null)
{
for (GoColor c : BLACK_WHITE)
for (GoPoint stone : node.getSetup(c))
printStone(c, stone, null);
Move move = node.getMove();
if (move == null)
{
node = node.getChildConst();
continue;
}
GoPoint point = move.getPoint();
GoColor color = move.getColor();
int moveNumber = NodeUtil.getMoveNumber(node);
boolean isColorUnexpected =
(blackToMove && color != BLACK)
|| (! blackToMove && color != WHITE);
boolean isPass = (point == null);
if (isPass || firstMoveAtPoint[point.getX()][point.getY()] != null)
{
needsComment.add(node);
m_out.print("\\pass");
if (! isPass)
{
m_out.print(" % \\move");
printCoordinates(point);
}
m_out.println(" % " + (blackToMove ? "B " : "W ") + moveNumber);
}
else
{
if (isColorUnexpected)
{
m_out.println("\\toggleblackmove");
blackToMove = ! blackToMove;
}
m_out.print("\\move");
printCoordinates(point);
m_out.println(" % " + (blackToMove ? "B " : "W ")
+ moveNumber);
firstMoveAtPoint[point.getX()][point.getY()] = node;
}
blackToMove = ! blackToMove;
node = node.getChildConst();
}
for (int i = 0; i < needsComment.size(); ++i)
{
node = needsComment.get(i);
int moveNumber = NodeUtil.getMoveNumber(node);
Move move = node.getMove();
GoPoint point = move.getPoint();
GoColor color = move.getColor();
if (comment.length() > 0)
comment.append(" \\enspace\n");
comment.append(getStoneInTextString(moveNumber, color));
if (point == null)
comment.append("~pass");
else
{
int x = point.getX();
int y = point.getY();
comment.append("~at~");
ConstNode first = firstMoveAtPoint[x][y];
GoColor firstMoveColor = first.getMove().getColor();
int firstMoveNumber = NodeUtil.getMoveNumber(first);
comment.append(getStoneInTextString(firstMoveNumber,
firstMoveColor));
}
}
return comment.toString();
}
private void printPosition(ConstBoard board, String[][] markLabel,
boolean[][] mark, boolean[][] markTriangle,
boolean[][] markCircle, boolean[][] markSquare,
boolean[][] markSelect)
{
for (GoPoint p : board)
{
GoColor color = board.getColor(p);
int x = p.getX();
int y = p.getY();
StringBuilder buffer = new StringBuilder(128);
if (mark != null && mark[x][y])
buffer.append("\\markma");
if (markTriangle != null && markTriangle[x][y])
buffer.append("\\marktr");
if (markCircle != null && markCircle[x][y])
buffer.append("\\markcr");
if (markSquare != null && markSquare[x][y])
buffer.append("\\marksq");
if (markLabel != null && ! StringUtil.isEmpty(markLabel[x][y]))
{
buffer.append("\\marklb{");
buffer.append(markLabel[x][y]);
buffer.append('}');
}
if (markSelect != null && markSelect[x][y])
buffer.append("\\marksl");
String markup = null;
if (buffer.length() > 0)
markup = buffer.toString();
if (color == EMPTY)
{
if (markup != null)
{
m_out.print("\\markpos{" + markup + "}");
printCoordinates(p);
m_out.print("\n");
}
}
else
printStone(color, p, markup);
}
}
private void printStone(GoColor color, GoPoint point, String markup)
{
m_out.print("\\stone");
if (markup != null)
m_out.print("[" + markup + "]");
printColor(color);
printCoordinates(point);
m_out.print("\n");
}
}