fixes to buggy MCTS code. Implemented rudimentary export of game state as SGF and LaTeX.
This commit is contained in:
@@ -19,6 +19,7 @@ public class GameBoard {
|
|||||||
private char[] board;
|
private char[] board;
|
||||||
private List<Integer> captureList;
|
private List<Integer> captureList;
|
||||||
private List<Long> boardHashHistory = new ArrayList<Long>();
|
private List<Long> boardHashHistory = new ArrayList<Long>();
|
||||||
|
|
||||||
private ZobristHashGenerator zobristHashGenerator;
|
private ZobristHashGenerator zobristHashGenerator;
|
||||||
|
|
||||||
public GameBoard(int size) {
|
public GameBoard(int size) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ public class GameState {
|
|||||||
private int whitePrisoners = 0;
|
private int whitePrisoners = 0;
|
||||||
private GameBoard gameBoard;
|
private GameBoard gameBoard;
|
||||||
private Player playerToMove;
|
private Player playerToMove;
|
||||||
|
private List<Action> moveHistory = new ArrayList<Action>();
|
||||||
|
|
||||||
public GameState(int size) {
|
public GameState(int size) {
|
||||||
if (size < 1 || size > 19) {
|
if (size < 1 || size > 19) {
|
||||||
@@ -22,6 +23,7 @@ public class GameState {
|
|||||||
this.whitePrisoners = that.whitePrisoners;
|
this.whitePrisoners = that.whitePrisoners;
|
||||||
this.playerToMove = that.playerToMove;
|
this.playerToMove = that.playerToMove;
|
||||||
gameBoard = new GameBoard(that.gameBoard);
|
gameBoard = new GameBoard(that.gameBoard);
|
||||||
|
moveHistory = new ArrayList<Action>(that.moveHistory);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearBoard() {
|
public void clearBoard() {
|
||||||
@@ -90,6 +92,8 @@ public class GameState {
|
|||||||
|
|
||||||
if (action.isPass()) {
|
if (action.isPass()) {
|
||||||
playerToMove = GoGame.getNextPlayer(player);
|
playerToMove = GoGame.getNextPlayer(player);
|
||||||
|
//TODO will need to record player as well
|
||||||
|
moveHistory.add(action);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +108,7 @@ public class GameState {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
assertCorrectHash();
|
//assertCorrectHash();
|
||||||
|
|
||||||
gameBoard.pushHashHistory();
|
gameBoard.pushHashHistory();
|
||||||
|
|
||||||
@@ -202,10 +206,12 @@ public class GameState {
|
|||||||
} else {
|
} else {
|
||||||
//assertCorrectHash();
|
//assertCorrectHash();
|
||||||
playerToMove = GoGame.getNextPlayer(player);
|
playerToMove = GoGame.getNextPlayer(player);
|
||||||
|
moveHistory.add(action);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
@Deprecated
|
@Deprecated
|
||||||
private void assertCorrectHash() {
|
private void assertCorrectHash() {
|
||||||
long hashFromHistory = gameBoard.getZobristHash();
|
long hashFromHistory = gameBoard.getZobristHash();
|
||||||
@@ -222,6 +228,15 @@ public class GameState {
|
|||||||
if (hashFromHistory != recalculatedHash) {
|
if (hashFromHistory != recalculatedHash) {
|
||||||
throw new RuntimeException("Zobrist hash code mismatch");
|
throw new RuntimeException("Zobrist hash code mismatch");
|
||||||
}
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
public boolean isTerminal() {
|
||||||
|
int nMoves = moveHistory.size();
|
||||||
|
if (nMoves < 2) {
|
||||||
|
return false; //Impossible for a game to be over in 1 move unless the first player resigns
|
||||||
|
//before the first player has played, the game is considered to be 'not over'
|
||||||
|
}
|
||||||
|
return moveHistory.get(nMoves-1).isPass() && moveHistory.get(nMoves-2).isPass();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|||||||
5
src/net/woodyfolsom/msproj/Referee.java
Normal file
5
src/net/woodyfolsom/msproj/Referee.java
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
package net.woodyfolsom.msproj;
|
||||||
|
|
||||||
|
public class Referee {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -34,9 +34,15 @@ public class MonteCarloUCT extends MonteCarlo {
|
|||||||
for (Action action : node.getActions()) {
|
for (Action action : node.getActions()) {
|
||||||
GameTreeNode<MonteCarloProperties> childNode = node.getChild(action);
|
GameTreeNode<MonteCarloProperties> childNode = node.getChild(action);
|
||||||
|
|
||||||
|
double childScore;
|
||||||
|
if (childNode.getGameState().isTerminal()) {
|
||||||
|
childScore = 0.0;
|
||||||
|
} else {
|
||||||
MonteCarloProperties properties = childNode.getProperties();
|
MonteCarloProperties properties = childNode.getProperties();
|
||||||
double childScore = (double) properties.getWins() / properties.getVisits() + TUNING_CONSTANT * Math.log(nodeVisits) / childNode.getProperties().getVisits();
|
childScore = (double) (properties.getWins() / properties.getVisits()) + (2 * TUNING_CONSTANT * Math.sqrt(2 * Math.log(nodeVisits) / childNode.getProperties().getVisits()));
|
||||||
|
}
|
||||||
|
//TODO add random tie breaker?
|
||||||
|
//otherwise the child that is selected first will be biased
|
||||||
if (childScore >= bestScore) {
|
if (childScore >= bestScore) {
|
||||||
bestScore = childScore;
|
bestScore = childScore;
|
||||||
bestNode = childNode;
|
bestNode = childNode;
|
||||||
@@ -128,7 +134,7 @@ public class MonteCarloUCT extends MonteCarlo {
|
|||||||
public void update(GameTreeNode<MonteCarloProperties> node, int reward) {
|
public void update(GameTreeNode<MonteCarloProperties> node, int reward) {
|
||||||
GameTreeNode<MonteCarloProperties> currentNode = node;
|
GameTreeNode<MonteCarloProperties> currentNode = node;
|
||||||
while (currentNode != null) {
|
while (currentNode != null) {
|
||||||
MonteCarloProperties nodeProperties = node.getProperties();
|
MonteCarloProperties nodeProperties = currentNode.getProperties();
|
||||||
nodeProperties.setWins(nodeProperties.getWins() + reward);
|
nodeProperties.setWins(nodeProperties.getWins() + reward);
|
||||||
nodeProperties.setVisits(nodeProperties.getVisits() + 1);
|
nodeProperties.setVisits(nodeProperties.getVisits() + 1);
|
||||||
currentNode = currentNode.getParent();
|
currentNode = currentNode.getParent();
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
package net.woodyfolsom.msproj.sgf;
|
|
||||||
|
|
||||||
public class CoordValue extends StrValue {
|
|
||||||
public final char column;
|
|
||||||
public final char row;
|
|
||||||
|
|
||||||
public CoordValue(String coord) {
|
|
||||||
super(coord);
|
|
||||||
|
|
||||||
column = coord.charAt(0);
|
|
||||||
row = coord.charAt(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package net.woodyfolsom.msproj.sgf;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class GameTree {
|
|
||||||
private List<Node> nodeSequence = new ArrayList<Node>();
|
|
||||||
private List<GameTree> subTrees = new ArrayList<GameTree>();
|
|
||||||
|
|
||||||
|
|
||||||
public int getNodeCount() {
|
|
||||||
return nodeSequence.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Node> getNodeSequence() {
|
|
||||||
return Collections.unmodifiableList(nodeSequence);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setNodeSequence(List<Node> nodeSequence) {
|
|
||||||
this.nodeSequence.clear();
|
|
||||||
|
|
||||||
for(Node node : nodeSequence) {
|
|
||||||
this.nodeSequence.add(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addSubTree(GameTree subTree) {
|
|
||||||
subTrees.add(subTree);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSubTreeCount() {
|
|
||||||
return subTrees.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
package net.woodyfolsom.msproj.sgf;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class Node {
|
|
||||||
private List<SGFProperty> properties = new ArrayList<SGFProperty>();
|
|
||||||
|
|
||||||
public void addProperty(SGFProperty property) {
|
|
||||||
properties.add(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getPropertyCount() {
|
|
||||||
return properties.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
package net.woodyfolsom.msproj.sgf;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class NodeCollection {
|
|
||||||
private List<GameTree> gameTrees = new ArrayList<GameTree>();
|
|
||||||
|
|
||||||
public void add(GameTree gameTree) {
|
|
||||||
gameTrees.add(gameTree);
|
|
||||||
}
|
|
||||||
|
|
||||||
public GameTree getGameTree(int index) {
|
|
||||||
return gameTrees.get(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getGameTreeCount() {
|
|
||||||
return gameTrees.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "foo";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package net.woodyfolsom.msproj.sgf;
|
|
||||||
|
|
||||||
public class PlayerIdent extends StrIdent {
|
|
||||||
public PlayerIdent(String player) {
|
|
||||||
super(player);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package net.woodyfolsom.msproj.sgf;
|
|
||||||
|
|
||||||
public class ResultValue extends StrValue {
|
|
||||||
public ResultValue(String result) {
|
|
||||||
super(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -24,4 +24,9 @@ public class SGFCoord {
|
|||||||
public char getRow() {
|
public char getRow() {
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new String(new char[]{column,row});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.woodyfolsom.msproj.Player;
|
||||||
|
|
||||||
public class SGFGameTree {
|
public class SGFGameTree {
|
||||||
private List<SGFNode> nodeSequence = new ArrayList<SGFNode>();
|
private List<SGFNode> nodeSequence = new ArrayList<SGFNode>();
|
||||||
private List<SGFGameTree> subTrees = new ArrayList<SGFGameTree>();
|
private List<SGFGameTree> subTrees = new ArrayList<SGFGameTree>();
|
||||||
@@ -32,4 +34,88 @@ public class SGFGameTree {
|
|||||||
public int getSubTreeCount() {
|
public int getSubTreeCount() {
|
||||||
return subTrees.size();
|
return subTrees.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toLateXmoves(Player player) {
|
||||||
|
StringBuilder latexSB = new StringBuilder();
|
||||||
|
SGFNode.TYPE nodeType;
|
||||||
|
SGFIdentifier sgfIdent;
|
||||||
|
if (player == Player.WHITE) {
|
||||||
|
nodeType = SGFNode.TYPE.MOVE_WHITE;
|
||||||
|
sgfIdent = SGFIdentifier.MOVE_WHITE;
|
||||||
|
latexSB.append("\\white{");
|
||||||
|
} else if (player == Player.BLACK) {
|
||||||
|
nodeType = SGFNode.TYPE.MOVE_BLACK;
|
||||||
|
sgfIdent = SGFIdentifier.MOVE_BLACK;
|
||||||
|
latexSB.append("\\black{");
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Invalid player: " + player);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean firstMove = true;
|
||||||
|
int nMoves = 0;
|
||||||
|
for (SGFNode node : nodeSequence) {
|
||||||
|
if (node.getType() != nodeType) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SGFValue<?> sgfValue = node.getFirstValue(sgfIdent);
|
||||||
|
if (sgfValue.isEmpty()) {
|
||||||
|
//TODO later this will be the LaTeX igo code for 'Pass'?
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (firstMove) {
|
||||||
|
firstMove = false;
|
||||||
|
} else {
|
||||||
|
latexSB.append(",");
|
||||||
|
}
|
||||||
|
SGFCoord sgfCoord = (SGFCoord) sgfValue.getValue();
|
||||||
|
char column = sgfCoord.getColumn();
|
||||||
|
if (column >= 'i') {
|
||||||
|
latexSB.append((char) (column + 1));
|
||||||
|
} else {
|
||||||
|
latexSB.append(column);
|
||||||
|
}
|
||||||
|
latexSB.append(19 - sgfCoord.getRow() + 'a');
|
||||||
|
nMoves++;
|
||||||
|
}
|
||||||
|
if (nMoves == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
latexSB.append("}\n");
|
||||||
|
return latexSB.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toLateX() {
|
||||||
|
StringBuilder latexSB = new StringBuilder();
|
||||||
|
|
||||||
|
//Somewhat convoluted logic here because the grammar does not require all root
|
||||||
|
//properties to be included in the same node in the tree's node sequence, although they should
|
||||||
|
//each be unique among all node sequences in the tree.
|
||||||
|
for (SGFNode node : nodeSequence) {
|
||||||
|
SGFNode.TYPE nodeType = node.getType();
|
||||||
|
switch (nodeType) {
|
||||||
|
case ROOT :
|
||||||
|
latexSB.append("\\gobansize");
|
||||||
|
latexSB.append("{");
|
||||||
|
latexSB.append(node.getFirstValue(SGFIdentifier.SIZE));
|
||||||
|
latexSB.append("}\n");
|
||||||
|
latexSB.append("\\shortstack{\\showfullgoban\\\\");
|
||||||
|
SGFResult result = (SGFResult) node.getFirstValue(SGFIdentifier.RESULT).getValue();
|
||||||
|
latexSB.append(result.getFullText());
|
||||||
|
latexSB.append("}\n");
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return latexSB.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toSGF() {
|
||||||
|
StringBuilder sgfFormatString = new StringBuilder("(");
|
||||||
|
for (SGFNode node : nodeSequence) {
|
||||||
|
sgfFormatString.append(node.toSGF());
|
||||||
|
}
|
||||||
|
sgfFormatString.append(")");
|
||||||
|
return sgfFormatString.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// $ANTLR 3.4 C:\\Users\\Woody\\Documents\\antlr\\SGF.g 2012-09-23 16:20:53
|
// $ANTLR 3.4 C:\\Users\\Woody\\Documents\\antlr\\SGF.g 2012-09-25 14:01:14
|
||||||
package net.woodyfolsom.msproj.sgf;
|
package net.woodyfolsom.msproj.sgf;
|
||||||
|
|
||||||
import org.antlr.runtime.*;
|
import org.antlr.runtime.*;
|
||||||
@@ -665,8 +665,8 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = LPAREN;
|
int _type = LPAREN;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:147:9: ( '(' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:150:9: ( '(' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:147:11: '('
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:150:11: '('
|
||||||
{
|
{
|
||||||
match('(');
|
match('(');
|
||||||
|
|
||||||
@@ -686,8 +686,8 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = SEMICOLON;
|
int _type = SEMICOLON;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:149:11: ( ';' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:152:11: ( ';' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:149:14: ';'
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:152:14: ';'
|
||||||
{
|
{
|
||||||
match(';');
|
match(';');
|
||||||
|
|
||||||
@@ -707,7 +707,7 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = UCLETTER;
|
int _type = UCLETTER;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:151:10: ( 'A' .. 'Z' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:154:10: ( 'A' .. 'Z' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:
|
||||||
{
|
{
|
||||||
if ( (input.LA(1) >= 'A' && input.LA(1) <= 'Z') ) {
|
if ( (input.LA(1) >= 'A' && input.LA(1) <= 'Z') ) {
|
||||||
@@ -736,7 +736,7 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = LCLETTER;
|
int _type = LCLETTER;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:153:10: ( 'a' .. 'z' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:156:10: ( 'a' .. 'z' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:
|
||||||
{
|
{
|
||||||
if ( (input.LA(1) >= 'a' && input.LA(1) <= 'z') ) {
|
if ( (input.LA(1) >= 'a' && input.LA(1) <= 'z') ) {
|
||||||
@@ -765,7 +765,7 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = DIGIT;
|
int _type = DIGIT;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:155:8: ( '0' .. '9' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:158:8: ( '0' .. '9' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:
|
||||||
{
|
{
|
||||||
if ( (input.LA(1) >= '0' && input.LA(1) <= '9') ) {
|
if ( (input.LA(1) >= '0' && input.LA(1) <= '9') ) {
|
||||||
@@ -794,8 +794,8 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = LBRACKET;
|
int _type = LBRACKET;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:158:2: ( '[' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:161:2: ( '[' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:158:4: '['
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:161:4: '['
|
||||||
{
|
{
|
||||||
match('[');
|
match('[');
|
||||||
|
|
||||||
@@ -815,8 +815,8 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = RBRACKET;
|
int _type = RBRACKET;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:161:2: ( ']' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:164:2: ( ']' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:161:4: ']'
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:164:4: ']'
|
||||||
{
|
{
|
||||||
match(']');
|
match(']');
|
||||||
|
|
||||||
@@ -836,8 +836,8 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = RPAREN;
|
int _type = RPAREN;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:163:9: ( ')' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:166:9: ( ')' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:163:11: ')'
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:166:11: ')'
|
||||||
{
|
{
|
||||||
match(')');
|
match(')');
|
||||||
|
|
||||||
@@ -857,8 +857,8 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = COLON;
|
int _type = COLON;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:165:8: ( ':' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:168:8: ( ':' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:165:10: ':'
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:168:10: ':'
|
||||||
{
|
{
|
||||||
match(':');
|
match(':');
|
||||||
|
|
||||||
@@ -878,8 +878,8 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = MINUS;
|
int _type = MINUS;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:167:8: ( '-' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:170:8: ( '-' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:167:10: '-'
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:170:10: '-'
|
||||||
{
|
{
|
||||||
match('-');
|
match('-');
|
||||||
|
|
||||||
@@ -899,8 +899,8 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = SPACE;
|
int _type = SPACE;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:169:8: ( ' ' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:172:8: ( ' ' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:169:10: ' '
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:172:10: ' '
|
||||||
{
|
{
|
||||||
match(' ');
|
match(' ');
|
||||||
|
|
||||||
@@ -920,8 +920,8 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = PERIOD;
|
int _type = PERIOD;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:171:9: ( '.' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:174:9: ( '.' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:171:11: '.'
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:174:11: '.'
|
||||||
{
|
{
|
||||||
match('.');
|
match('.');
|
||||||
|
|
||||||
@@ -941,8 +941,8 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = COMMA;
|
int _type = COMMA;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:173:8: ( ',' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:176:8: ( ',' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:173:10: ','
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:176:10: ','
|
||||||
{
|
{
|
||||||
match(',');
|
match(',');
|
||||||
|
|
||||||
@@ -962,8 +962,8 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = PLUS;
|
int _type = PLUS;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:175:7: ( '+' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:178:7: ( '+' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:175:9: '+'
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:178:9: '+'
|
||||||
{
|
{
|
||||||
match('+');
|
match('+');
|
||||||
|
|
||||||
@@ -983,8 +983,8 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = SLASH;
|
int _type = SLASH;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:177:8: ( '/' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:180:8: ( '/' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:177:10: '/'
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:180:10: '/'
|
||||||
{
|
{
|
||||||
match('/');
|
match('/');
|
||||||
|
|
||||||
@@ -1004,8 +1004,8 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = CR;
|
int _type = CR;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:179:5: ( '\\r' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:182:5: ( '\\r' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:179:7: '\\r'
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:182:7: '\\r'
|
||||||
{
|
{
|
||||||
match('\r');
|
match('\r');
|
||||||
|
|
||||||
@@ -1027,8 +1027,8 @@ public class SGFLexer extends Lexer {
|
|||||||
try {
|
try {
|
||||||
int _type = NEWLINE;
|
int _type = NEWLINE;
|
||||||
int _channel = DEFAULT_TOKEN_CHANNEL;
|
int _channel = DEFAULT_TOKEN_CHANNEL;
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:181:9: ( '\\n' )
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:184:9: ( '\\n' )
|
||||||
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:181:11: '\\n'
|
// C:\\Users\\Woody\\Documents\\antlr\\SGF.g:184:11: '\\n'
|
||||||
{
|
{
|
||||||
match('\n');
|
match('\n');
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,55 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SGFNode {
|
public class SGFNode {
|
||||||
|
public enum TYPE { ROOT, MOVE_BLACK, MOVE_WHITE, EMPTY }
|
||||||
|
|
||||||
private List<SGFProperty> properties = new ArrayList<SGFProperty>();
|
private List<SGFProperty> properties = new ArrayList<SGFProperty>();
|
||||||
|
private TYPE type = TYPE.EMPTY;
|
||||||
|
|
||||||
public void addProperty(SGFProperty property) {
|
public void addProperty(SGFProperty property) {
|
||||||
|
if (properties.size() == 0) {
|
||||||
|
SGFIdentifier sgfIdent = property.getIdentifier();
|
||||||
|
if (sgfIdent == SGFIdentifier.MOVE_BLACK) {
|
||||||
|
type = TYPE.MOVE_BLACK;
|
||||||
|
} else if (sgfIdent == SGFIdentifier.MOVE_WHITE) {
|
||||||
|
type = TYPE.MOVE_WHITE;
|
||||||
|
} else {
|
||||||
|
type = TYPE.ROOT;
|
||||||
|
}
|
||||||
|
}
|
||||||
properties.add(property);
|
properties.add(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getPropertyCount() {
|
public int getPropertyCount() {
|
||||||
return properties.size();
|
return properties.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TYPE getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SGFValue<?> getFirstValue(SGFIdentifier identifier) {
|
||||||
|
for (int i = 0; i < properties.size(); i++) {
|
||||||
|
if (identifier == properties.get(i).getIdentifier()) {
|
||||||
|
return properties.get(i).getValues().get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException("SGFNode does not contain a property with identifier '" + identifier +"'");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toSGF() {
|
||||||
|
if (properties.size() == 0) {
|
||||||
|
throw new RuntimeException("SGFNode contains no properties");
|
||||||
|
}
|
||||||
|
|
||||||
|
SGFProperty firstProp = properties.get(0);
|
||||||
|
|
||||||
|
String sgfFormatString = ";" + firstProp.toSGF();
|
||||||
|
|
||||||
|
for (int i = 1; i < properties.size(); i++) {
|
||||||
|
sgfFormatString += properties.get(i).toSGF();
|
||||||
|
}
|
||||||
|
|
||||||
|
return sgfFormatString;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package net.woodyfolsom.msproj.sgf;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import net.woodyfolsom.msproj.Player;
|
||||||
|
|
||||||
public class SGFNodeCollection {
|
public class SGFNodeCollection {
|
||||||
private List<SGFGameTree> gameTrees = new ArrayList<SGFGameTree>();
|
private List<SGFGameTree> gameTrees = new ArrayList<SGFGameTree>();
|
||||||
|
|
||||||
@@ -18,8 +20,29 @@ public class SGFNodeCollection {
|
|||||||
return gameTrees.size();
|
return gameTrees.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toLateX() {
|
||||||
|
StringBuilder latexFormatString = new StringBuilder("");
|
||||||
|
SGFGameTree gameTree = gameTrees.get(0);
|
||||||
|
|
||||||
|
latexFormatString.append(gameTree.toLateXmoves(Player.BLACK));
|
||||||
|
latexFormatString.append(gameTree.toLateXmoves(Player.WHITE));
|
||||||
|
latexFormatString.append("\\begin{center}\n");
|
||||||
|
latexFormatString.append(gameTree.toLateX());
|
||||||
|
latexFormatString.append("\\end{center}");
|
||||||
|
|
||||||
|
return latexFormatString.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toSGF() {
|
||||||
|
String sgfFormatString = "";
|
||||||
|
for (SGFGameTree gameTree : gameTrees) {
|
||||||
|
sgfFormatString += gameTree.toSGF();
|
||||||
|
}
|
||||||
|
return sgfFormatString;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "foo";
|
return toSGF();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class SGFProperty {
|
public class SGFProperty {
|
||||||
private SGFIdentifier ident;
|
private SGFIdentifier identifier;
|
||||||
private List<SGFValue<?>> values = new ArrayList<SGFValue<?>>();
|
private List<SGFValue<?>> values = new ArrayList<SGFValue<?>>();
|
||||||
|
|
||||||
public void addValue(SGFValue<?> value) {
|
public void addValue(SGFValue<?> value) {
|
||||||
@@ -13,7 +13,7 @@ public class SGFProperty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SGFIdentifier getIdentifier() {
|
public SGFIdentifier getIdentifier() {
|
||||||
return ident;
|
return identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<SGFValue<?>> getValues() {
|
public List<SGFValue<?>> getValues() {
|
||||||
@@ -21,6 +21,19 @@ public class SGFProperty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setIdentifier(SGFIdentifier ident) {
|
public void setIdentifier(SGFIdentifier ident) {
|
||||||
this.ident = ident;
|
this.identifier = ident;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toSGF() {
|
||||||
|
if (values.size() == 0) {
|
||||||
|
return identifier + "[]";
|
||||||
|
}
|
||||||
|
|
||||||
|
String sgfFormatString = identifier + "[" + values.get(0) + "]";
|
||||||
|
for (int i = 1; i < values.size(); i++) {
|
||||||
|
sgfFormatString += "[" + values.get(i) + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
return sgfFormatString;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,16 @@ public class SGFResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getFullText() {
|
||||||
|
if (resignation == false && tie == false) {
|
||||||
|
return winner.getColor() + " wins by " + score;
|
||||||
|
} else if (resignation == true && tie == false) {
|
||||||
|
return winner.getColor() + " wins by resignation";
|
||||||
|
} else {
|
||||||
|
throw new UnsupportedOperationException("Not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
if (resignation == false && tie == false) {
|
if (resignation == false && tie == false) {
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ public class SGFValue<T> {
|
|||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return text.length() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
public String getText() {
|
public String getText() {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
@@ -18,4 +22,9 @@ public class SGFValue<T> {
|
|||||||
public T getValue() {
|
public T getValue() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
package net.woodyfolsom.msproj.sgf;
|
|
||||||
|
|
||||||
public class SGFWriter {
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
(;FF[4]GM[1]SZ[19]CA[UTF-8]SO[gokifu.com]BC[kr]WC[cn]EV[]PB[Lee Sedol]BR[9p]PW[Gu Li]WR[9p]KM[7.5]
|
||||||
|
DT[2012-09-16]RE[W+R];B[qd];W[dc];B[dq];W[do];B[pp];W[cq];B[de];W[cg];B[cc];W[gc];B[gd];W[hd];B[fc]
|
||||||
|
;W[fd];B[ge];W[fb];B[hc];W[ec];B[gb];W[fc];B[id];W[cd];B[he];W[oc];B[pe];W[qk];B[qi];W[qn];B[qo]
|
||||||
|
;W[pn];B[np];W[oj];B[oi];W[ni];B[nj];W[pi];B[oh];W[pj];B[ph];W[qh];B[qg];W[rh];B[ri];W[rg];B[rf]
|
||||||
|
;W[oo];B[op];W[mj];B[mc];W[nk];B[cr];W[cp];B[gq];W[md];B[nc];W[qf];B[sh];W[pg];B[sg];W[od];B[nd]
|
||||||
|
;W[oe];B[ne];W[nf];B[qg];W[og];B[nh];W[mh];B[mg];W[ng];B[qh];W[mf];B[lg];W[lf];B[ld];W[qc];B[rc]
|
||||||
|
;W[pb];B[rb];W[kg];B[lh];W[mi];B[dl];W[br];B[ce];W[bd];B[dg];W[dh];B[be];W[eg];B[fe];W[dd];B[df]
|
||||||
|
;W[ci];B[gl];W[fh];B[ad];W[bc];B[dr];W[dm];B[em];W[cm];B[gg];W[gh];B[jq];W[fo];B[il];W[hg];B[ho]
|
||||||
|
;W[lo];B[lq];W[kp];B[kq];W[ee];B[ef];W[ff];B[ed];W[gp];B[hq];W[ee];B[pf];W[of];B[ed];W[gn];B[ei]
|
||||||
|
;W[eh];B[ii];W[kd];B[kc];W[ke];B[nb];W[fl];B[fk];W[ek];B[fj];W[dj];B[gf];W[gm];B[kh];W[jh];B[jg]
|
||||||
|
;W[ig];B[jf];W[jd];B[je];W[kf];B[ki];W[jc];B[kb];W[jb];B[ib];W[ja];B[ob];W[ic];B[ih];W[ha];B[hb]
|
||||||
|
;W[ga];B[ma];W[hh];B[hk];W[kl];B[kk];W[jk];B[jj];W[lk];B[bg];W[bh];B[cf];W[ch];B[ag];W[ac];B[el]
|
||||||
|
;W[fm];B[ae];W[rn];B[ro];W[fq];B[fr];W[so];B[sp];W[sn];B[rp];W[gj];B[hj];W[ej];B[fi];W[gi];B[gk]
|
||||||
|
;W[bj];B[jl];W[kj];B[ik];W[fg];B[ee];W[eq];B[er];W[km];B[bs];W[ar];B[rk];W[rl];B[qj];W[no];B[mp]
|
||||||
|
;W[ql];B[qb];W[ia];B[hd];W[pc];B[pa];W[jo];B[hm];W[dp])
|
||||||
57
test/net/woodyfolsom/msproj/sgf/CollectionTest.java
Normal file
57
test/net/woodyfolsom/msproj/sgf/CollectionTest.java
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package net.woodyfolsom.msproj.sgf;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.antlr.runtime.ANTLRInputStream;
|
||||||
|
import org.antlr.runtime.ANTLRStringStream;
|
||||||
|
import org.antlr.runtime.CommonTokenStream;
|
||||||
|
import org.antlr.runtime.RecognitionException;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class CollectionTest {
|
||||||
|
public static final String TEST_SGF =
|
||||||
|
"(;FF[4]SZ[9]KM[5.5]RE[W+6.5]"+
|
||||||
|
";W[ee];B[];W[])";
|
||||||
|
public static final String TEST_LATEX =
|
||||||
|
"\\white{e5}\n" +
|
||||||
|
"\\begin{center}\n" +
|
||||||
|
"\\gobansize{9}\n" +
|
||||||
|
"\\shortstack{\\showfullgoban\\\\White wins by 6.5}\n" +
|
||||||
|
"\\end{center}";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToSGF() throws RecognitionException, IOException {
|
||||||
|
ByteArrayInputStream bis = new ByteArrayInputStream(
|
||||||
|
("(;FF[4]SZ[9]KM[5.5]RE[W+6.5]" +
|
||||||
|
";W[ee];B[];W[])"
|
||||||
|
).getBytes());
|
||||||
|
ANTLRStringStream in = new ANTLRInputStream(bis);
|
||||||
|
SGFLexer lexer = new SGFLexer(in);
|
||||||
|
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||||
|
SGFParser parser = new SGFParser(tokens);
|
||||||
|
SGFNodeCollection nodeCollection = parser.collection();
|
||||||
|
|
||||||
|
assertEquals(TEST_SGF, nodeCollection.toSGF());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testToLaTeX() throws RecognitionException, IOException {
|
||||||
|
ByteArrayInputStream bis = new ByteArrayInputStream(
|
||||||
|
("(;FF[4]SZ[9]RE[W+6.5]" +
|
||||||
|
";W[ee];B[];W[])"
|
||||||
|
).getBytes());
|
||||||
|
ANTLRStringStream in = new ANTLRInputStream(bis);
|
||||||
|
SGFLexer lexer = new SGFLexer(in);
|
||||||
|
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||||
|
SGFParser parser = new SGFParser(tokens);
|
||||||
|
SGFNodeCollection nodeCollection = parser.collection();
|
||||||
|
|
||||||
|
assertEquals(TEST_LATEX, nodeCollection.toLateX());
|
||||||
|
}
|
||||||
|
}
|
||||||
34
test/net/woodyfolsom/msproj/sgf/SGFParserTest.java
Normal file
34
test/net/woodyfolsom/msproj/sgf/SGFParserTest.java
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package net.woodyfolsom.msproj.sgf;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.antlr.runtime.ANTLRInputStream;
|
||||||
|
import org.antlr.runtime.ANTLRStringStream;
|
||||||
|
import org.antlr.runtime.CommonTokenStream;
|
||||||
|
import org.antlr.runtime.RecognitionException;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class SGFParserTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParse() throws RecognitionException, IOException {
|
||||||
|
FileInputStream fis = new FileInputStream(new File("data/games/1334-gokifu-20120916-Gu_Li-Lee_Sedol.sgf"));
|
||||||
|
ANTLRStringStream in = new ANTLRInputStream(fis);
|
||||||
|
SGFLexer lexer = new SGFLexer(in);
|
||||||
|
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||||
|
SGFParser parser = new SGFParser(tokens);
|
||||||
|
SGFNodeCollection nodeCollection = parser.collection();
|
||||||
|
|
||||||
|
System.out.println("To SGF:");
|
||||||
|
System.out.println(nodeCollection.toSGF());
|
||||||
|
System.out.println("");
|
||||||
|
|
||||||
|
System.out.println("To LaTeX:");
|
||||||
|
System.out.println(nodeCollection.toLateX());
|
||||||
|
System.out.println("");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user