Able to export SGF files from successful games.

This commit is contained in:
2012-11-14 11:14:38 -05:00
parent 105b4c0187
commit 4d38c2bc20
28 changed files with 7231 additions and 6505 deletions

View File

@@ -44,7 +44,8 @@ $sgfProperty = new SGFProperty();
| (strIdent{$sgfProperty.setIdentifier($strIdent.sgfIdent);}) ((LBRACKET RBRACKET){$sgfProperty.addValue(SGFValue.EMPTY);})
| (strIdent{$sgfProperty.setIdentifier($strIdent.sgfIdent);}) ((LBRACKET strValue RBRACKET){$sgfProperty.addValue(new SGFValue<String>($strValue.text));})+
| (result{$sgfProperty.setIdentifier(SGFIdentifier.RESULT);}) ((LBRACKET resValue RBRACKET){$sgfProperty.addValue(new SGFValue<SGFResult>(new SGFResult($resValue.text)));})+
| (result{$sgfProperty.setIdentifier(SGFIdentifier.RESULT);}) ((LBRACKET strValue RBRACKET){$sgfProperty.addValue(new SGFValue<SGFResult>(new SGFResult($strValue.text)));})+
| (komi{$sgfProperty.setIdentifier(SGFIdentifier.KOMI);}) ((LBRACKET realValue RBRACKET){$sgfProperty.addValue(new SGFValue<Double>(Double.parseDouble($realValue.text)));})+
| (coordIdent{$sgfProperty.setIdentifier($coordIdent.sgfIdent);})((LBRACKET coordValue RBRACKET){$sgfProperty.addValue(new SGFValue<SGFCoord>(new SGFCoord($coordValue.text)));})+
;
@@ -53,27 +54,32 @@ $sgfProperty = new SGFProperty();
playerIdent returns [SGFIdentifier sgfPlayer]
: {(input.LT(1).getText().equals("W"))}? strIdent {$sgfPlayer = $strIdent.sgfIdent;}
| {(input.LT(1).getText().equals("B"))}? strIdent {$sgfPlayer = $strIdent.sgfIdent;}
| {(input.LT(1).getText().equals("White"))}? strIdent {$sgfPlayer = $strIdent.sgfIdent;}
| {(input.LT(1).getText().equals("Black"))}? strIdent {$sgfPlayer = $strIdent.sgfIdent;}
;
strIdent returns [SGFIdentifier sgfIdent]
: charEnc{$sgfIdent = SGFIdentifier.CHARSET;}
| source
| blackCountry
| whiteCountry
| event
| playerBlack
| playerWhite
| blackRank
| whiteRank
| result
| rules
| place
| application
| source{$sgfIdent = SGFIdentifier.SOURCE;}
| blackCountry{$sgfIdent = SGFIdentifier.COUNTRY_BLACK;}
| whiteCountry{$sgfIdent = SGFIdentifier.COUNTRY_WHITE;}
| event{$sgfIdent = SGFIdentifier.EVENT;}
| playerBlack{$sgfIdent = SGFIdentifier.PLAYER_BLACK;}
| playerWhite{$sgfIdent = SGFIdentifier.PLAYER_WHITE;}
| blackRank{$sgfIdent = SGFIdentifier.RANK_BLACK;}
| whiteRank{$sgfIdent = SGFIdentifier.RANK_WHITE;}
| rules{$sgfIdent = SGFIdentifier.RULES;}
| place{$sgfIdent = SGFIdentifier.PLACE;}
| application{$sgfIdent = SGFIdentifier.APPLICATION;}
| copyright
| username
| date
| date{$sgfIdent = SGFIdentifier.DATE;}
| 'Black'{$sgfIdent = SGFIdentifier.MOVE_BLACK;}
| 'White'{$sgfIdent = SGFIdentifier.MOVE_WHITE;}
| 'B'{$sgfIdent = SGFIdentifier.MOVE_BLACK;}
| 'W'{$sgfIdent = SGFIdentifier.MOVE_WHITE;}
| view{$sgfIdent = SGFIdentifier.VIEW;} //this is not really a strIdent, but is a placeholder since I don't use this info
| comment{$sgfIdent = SGFIdentifier.COMMENT;}
//SGF grammar proper allows extensions, but this reader does not
; //if this is matched from rule playerIdent, the value is thrown away - this rule alone
//lack the context to disambiguate the single-character player movement IDs.
@@ -90,48 +96,65 @@ numIdent returns [SGFIdentifier sgfIdent]
| time{$sgfIdent = SGFIdentifier.TIME;};
numValue returns [SGFValue<Integer> sgfValue]
: (DIGIT+){$sgfValue = new SGFValue<Integer>(Integer.parseInt($numValue.text));};
: (STRVALUE){$sgfValue = new SGFValue<Integer>(Integer.parseInt($numValue.text));};
realIdent
: komi;
resValue //'R' is resign
: playerIdent PLUS ('R' | realValue);
realValue
: DIGIT+ PERIOD DIGIT+;
: STRVALUE;
coordValue returns [SGFCoord sgfCoord]
: LCLETTER LCLETTER {$sgfCoord = new SGFCoord($text);}
: STRVALUE {$sgfCoord = new SGFCoord($coordValue.text);}
;
fileFormat
: 'FF';
game : 'GM';
size : 'SZ';
game : 'GM' | 'GaMe';
size : 'SZ' | 'SiZe';
view : 'VW' | 'VieW';
charEnc : 'CA';
source : 'SO';
blackCountry
: 'BC';
whiteCountry
: 'WC';
event : 'EV';
event : 'EV' | 'EVent';
playerBlack
: 'PB';
: 'PB' | 'PlayerBlack';
playerWhite
: 'PW';
: 'PW' | 'PlayerWhite';
blackRank
: 'BR';
whiteRank
: 'WR';
komi : 'KM';
result : 'RE';
result : 'RE'
| 'REsult'
;
rules : 'RU';
place : 'PC';
place : 'PC' | 'PlaCe';
application
: 'AP';
time : 'TM';
date : 'DT';
date : 'DT' | 'DaTe';
addBlack returns [SGFIdentifier sgfIdent]
: 'AB'{$sgfIdent = SGFIdentifier.ADD_BLACK;}
@@ -143,19 +166,40 @@ addWhite returns [SGFIdentifier sgfIdent]
copyright
: 'CP';
username: 'US';
strValue : (UCLETTER | LCLETTER | MINUS | DIGIT | SPACE | PERIOD | COMMA | PLUS | SLASH | COLON)+;
comment : 'C';
strValue
: (STRVALUE)+;
SPACE : ' ';
fragment DIGIT : '0'..'9';
COLON : ':';
MINUS : '-';
fragment PERIOD : '.';
COMMA : ',';
PLUS : '+';
SLASH : '/';
STRVALUE : (UCLETTER | LCLETTER | MINUS | DIGIT | SPACE | PERIOD | COMMA | PLUS | SLASH | COLON )+;
LPAREN : '(' ;
SEMICOLON : ';' ;
UCLETTER : 'A'..'Z';
fragment UCLETTER : 'A'..'Z';
LCLETTER : 'a'..'z';
DIGIT : '0'..'9';
fragment LCLETTER : 'a'..'z';
LBRACKET
: '[';
@@ -165,20 +209,6 @@ RBRACKET
RPAREN : ')';
COLON : ':';
//CR : '\r'{$channel=HIDDEN;};
MINUS : '-';
SPACE : ' ';
PERIOD : '.';
COMMA : ',';
PLUS : '+';
SLASH : '/';
CR : '\r'{$channel=HIDDEN;};
NEWLINE : '\n'{$channel=HIDDEN;};
//NEWLINE : '\n'{$channel=HIDDEN;};

View File

@@ -28,7 +28,7 @@ DaTe[1968]
PlaCe[]
REsult[Black wins by four points]
REsult[B+4]
C[This was the first of a two game match on 9x9, played

View File

@@ -0,0 +1,118 @@
package net.woodyfolsom.msproj;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class GameRecord {
public enum RULES { JAPANESE, CHINESE }
private GoPlayer playerBlack;
private GoPlayer playerWhite;
//private int numTurns = 0;
private List<Action> moves = new ArrayList<Action>();
private List<GameState> gameStates = new ArrayList<GameState>();
private Map<Integer, List<String>> comments = new HashMap<Integer,List<String>>();
private RULES rules = RULES.CHINESE;
public GameRecord(GameConfig gameConfig) {
gameStates.add(new GameState(gameConfig));
//initial 'move' of Action.NONE allows for a game that starts with a board setup
moves.add(Action.NONE);
}
/**
* Adds a comment for the current turn.
* @param comment
*/
public void addComment(String comment) {
if (comments.containsKey(getNumTurns())) {
comments.get(getNumTurns()).add(comment);
} else {
List<String> newComments = new ArrayList<String>();
newComments.add(comment);
comments.put(getNumTurns(),newComments);
}
}
public List<String> getComments(Integer turn) {
if (comments.containsKey(turn)) {
return Collections.unmodifiableList(comments.get(turn));
} else {
return new ArrayList<String>(0);
}
}
public GameConfig getGameConfig() {
return gameStates.get(0).getGameConfig();
}
public GameState getGameState(Integer turn) {
return gameStates.get(turn);
}
public Action getMove(int turn) {
return moves.get(turn);
}
public int getNumTurns() {
return gameStates.size() - 1;
}
public Player getPlayerToMove(int turn) {
return gameStates.get(turn).getPlayerToMove();
}
public Player getPlayerToMove() {
return gameStates.get(getNumTurns()).getPlayerToMove();
}
public GameResult getResult() {
return gameStates.get(getNumTurns()).getResult();
}
public RULES getRules() {
return rules;
}
public boolean isFinished() {
return gameStates.get(getNumTurns()).isTerminal();
}
public boolean play(Player player, Action action) {
if (isFinished()) {
System.out.println("Unable to play " + action + " as " + player + " because the game is finished.");
return false; //cannot make any more moves, game is over
}
GameState nextState = new GameState(gameStates.get(getNumTurns()));
if (nextState.playStone(player, action)) {
gameStates.add(nextState);
moves.add(action);
return true;
} else {
//TODO allow relay of an SGF to force making an invalid move?
//It may be possible historically for a mistake to have been made,
//and recorded.
System.out.println("Invalid move" + " by " + player + ": " + action);
return false; //invalid move for this player at this time
}
}
public void setPlayer(Player player, String name, String country, String rank) {
if (player == Player.BLACK) {
playerBlack = new GoPlayer();
playerBlack.setName(name);
playerBlack.setRank(rank);
playerBlack.setCountry(country);
} else if (player == Player.WHITE) {
playerWhite = new GoPlayer();
playerWhite.setName(name);
playerWhite.setRank(rank);
} else {
throw new RuntimeException("Invalid color: " + player);
}
}
}

View File

@@ -0,0 +1,42 @@
package net.woodyfolsom.msproj;
public class GoPlayer {
private String country;
private String name;
private String rank;
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRank() {
return rank;
}
public void setRank(String rank) {
this.rank = rank;
}
public String toSGF(Player color) {
if (color == Player.BLACK) {
return "PB[" + name + "]BR[" + rank + "]BC[" + country + "]";
} else if (color == Player.WHITE) {
return "PW[" + name + "]WR[" + rank + "]WC[" + country + "]";
} else {
throw new RuntimeException("Invalid player color: " + color);
}
}
}

View File

@@ -36,18 +36,25 @@ public class Referee {
}
public GameResult play(GameConfig gameConfig) {
GameState gameState = new GameState(gameConfig);
GameRecord gameRecord = new GameRecord(gameConfig);
System.out.println("Game started.");
try {
while (!gameState.isTerminal()) {
while (!gameRecord.isFinished()) {
GameState gameState = gameRecord.getGameState(gameRecord.getNumTurns());
System.out.println(gameState);
Player currentPlayer = gameState.getPlayerToMove();
Action action = getPolicy(currentPlayer).getAction(gameConfig,
gameState, currentPlayer);
gameState.playStone(currentPlayer, action);
Player playerToMove = gameRecord.getPlayerToMove();
Policy policy = getPolicy(playerToMove);
Action action = policy.getAction(gameConfig,
gameState, playerToMove);
if (gameRecord.play(playerToMove, action)) {
policy.setState(gameRecord.getGameState(gameRecord.getNumTurns()));
} else {
System.out.println("Move rejected - try again.");
}
}
} catch (Exception ex) {
System.out
@@ -56,7 +63,7 @@ public class Referee {
return GameResult.VOID;
}
GameResult result = gameState.getResult();
GameResult result = gameRecord.getResult();
System.out.println("Game over. Result: " + result);
@@ -68,7 +75,7 @@ public class Referee {
+ ".sgf");
FileOutputStream fos = new FileOutputStream(sgfFile);
try {
SGFWriter.writeSGF(gameState, fos);
SGFWriter.write(fos, gameRecord);
System.out
.println("Game saved as " + sgfFile.getAbsolutePath());
} finally {

View File

@@ -2,21 +2,45 @@ package net.woodyfolsom.msproj;
import java.io.IOException;
import java.io.OutputStream;
import net.woodyfolsom.msproj.sgf.SGFIdentifier;
import java.io.OutputStreamWriter;
public class SGFWriter {
public static void writeSGF(GameState gameState, OutputStream os)
public static void write(OutputStream os, GameRecord gameRecord)
throws IOException {
writeNode(os, SGFIdentifier.FILE_FORMAT, Integer.valueOf(4));
}
OutputStreamWriter writer = new OutputStreamWriter(os);
private static void writeNode(OutputStream os, SGFIdentifier sgfIdent,
Object nodeValue) throws IOException {
os.write(sgfIdent.toString().getBytes());
os.write("[".getBytes());
os.write(nodeValue.toString().getBytes());
os.write("];".getBytes());
writer.write("(");
writer.write(";FF[4]GM[1]");
GameConfig gameConfig = gameRecord.getGameConfig();
writer.write("SZ[" + gameConfig.getSize() + "]");
writer.write("KM[" + gameConfig.getKomi() + "]");
for (int i = 1; i <= gameRecord.getNumTurns(); i++) {
Player player = gameRecord.getPlayerToMove(i-1);
if (Player.BLACK == player) {
writer.write(";B[");
} else if (Player.WHITE == player) {
writer.write(";W[");
} else {
throw new RuntimeException("Invalid player: " + player);
}
Action action = gameRecord.getMove(i);
String sgfCoord;
if (action.isPass()) {
sgfCoord = "";
} else {
sgfCoord = action.toString().toLowerCase().substring(0,1);
char row = (char) ('a' + gameConfig.getSize() - Integer.valueOf(action.toString().substring(1)).intValue());
sgfCoord = sgfCoord + row;
}
writer.write(sgfCoord + "]");
}
writer.write(")");
writer.flush();
}
}

View File

@@ -1,39 +1,54 @@
package net.woodyfolsom.msproj.gui;
import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.Player;
public class Goban extends JFrame implements KeyListener {
public class Goban extends JFrame {
private static final long serialVersionUID = 1L;
//private GameState gameState;
private GridPanel gridPanel;
/*
public static void main(String[] args) {
Goban goban = new Goban();
goban.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
goban.setVisible(true);
goban.pack();
}*/
public Goban(GameConfig gameConfig, Player guiPlayer) {
setLayout(new BorderLayout());
this.gridPanel = new GridPanel(gameConfig, guiPlayer);
add(gridPanel,BorderLayout.CENTER);
addKeyListener(this);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
JButton passBtn = new JButton("Pass");
JButton resignBtn = new JButton("Resign");
passBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
gridPanel.addAction(Action.PASS);
}});
resignBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
gridPanel.addAction(Action.RESIGN);
}});
JPanel bottomPanel = new JPanel();
bottomPanel.add(passBtn);
bottomPanel.add(resignBtn);
add(bottomPanel, BorderLayout.SOUTH);
pack();
}
@@ -45,31 +60,4 @@ public class Goban extends JFrame implements KeyListener {
gridPanel.setGameState(gameState);
}
@Override
public void keyPressed(KeyEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent arg0) {
switch (arg0.getKeyChar())
{
/*
case 't' :
case 'T' :
//Player currentPlayer = GoGame.getNextPlayer(gameState.getPlayerToMove());
//System.out.println("Switching players. Current player is now " + currentPlayer);
//gameState.
break;*/
default :
System.out.println("Ignoring unbound key: " + arg0.getKeyChar());
}
}
}

View File

@@ -76,8 +76,12 @@ public class GridPanel extends JPanel implements MouseListener,
}
}
public void addAction(Action action) {
actionQueue.add(action);
}
public Action getAction() {
int timeLimit = 10;
int timeLimit = 30;
TimeUnit timeUnit = TimeUnit.SECONDS;
try {
@@ -212,6 +216,7 @@ public class GridPanel extends JPanel implements MouseListener,
public void setGameState(GameState gameState) {
this.gameState = gameState;
this.repaint();
}
@Override

View File

@@ -176,4 +176,10 @@ public class AlphaBeta implements Policy {
throw new UnsupportedOperationException(
"Prohibited actions not supported by this class.");
}
@Override
public void setState(GameState gameState) {
// TODO Auto-generated method stub
}
}

View File

@@ -1,6 +1,5 @@
package net.woodyfolsom.msproj.policy;
import java.io.IOException;
import java.util.Collection;
import net.woodyfolsom.msproj.Action;
@@ -20,7 +19,6 @@ public class HumanGuiInput implements Policy {
public Action getAction(GameConfig gameConfig, GameState gameState,
Player player) {
Action action = null;
String input = "";
do {
System.out.println(player
@@ -30,8 +28,6 @@ public class HumanGuiInput implements Policy {
action = goban.getAction();
if (action.isNone()) {
System.out.println("No move was made within 10 seconds. Hurry up!");
System.out.println(gameState);
continue;
}
} while (action == null);
@@ -51,4 +47,9 @@ public class HumanGuiInput implements Policy {
return 1;
}
@Override
public void setState(GameState gameState) {
goban.setGameState(gameState);
}
}

View File

@@ -70,4 +70,10 @@ public class HumanKeyboardInput implements Policy {
return 1;
}
@Override
public void setState(GameState gameState) {
// TODO Auto-generated method stub
}
}

View File

@@ -149,4 +149,10 @@ public class Minimax implements Policy {
throw new UnsupportedOperationException(
"Prohibited actions not supported by this class.");
}
@Override
public void setState(GameState gameState) {
// TODO Auto-generated method stub
}
}

View File

@@ -13,7 +13,7 @@ import net.woodyfolsom.msproj.tree.GameTreeNode;
import net.woodyfolsom.msproj.tree.MonteCarloProperties;
public abstract class MonteCarlo implements Policy {
protected static final int ROLLOUT_DEPTH_LIMIT = 400;
protected static final int ROLLOUT_DEPTH_LIMIT = 100;
protected int numStateEvaluations = 0;
protected Policy movePolicy;
@@ -113,10 +113,6 @@ public abstract class MonteCarlo implements Policy {
return searchTimeLimit;
}
public int doRollout() {
return 0;
}
public int getNumStateEvaluations() {
return numStateEvaluations;
}

View File

@@ -196,4 +196,10 @@ public class MonteCarloUCT extends MonteCarlo {
public String toString() {
return "MonteCarloUCT";
}
@Override
public void setState(GameState gameState) {
// TODO Auto-generated method stub
}
}

View File

@@ -15,4 +15,6 @@ public interface Policy {
Collection<Action> prohibitedActions, Player player);
public int getNumStateEvaluations();
public void setState(GameState gameState);
}

View File

@@ -83,4 +83,10 @@ public class RandomMovePolicy implements Policy, ActionGenerator {
Player player) {
return getActions(gameConfig, gameState, player, 1).get(0);
}
@Override
public void setState(GameState gameState) {
// TODO Auto-generated method stub
}
}

View File

@@ -147,4 +147,10 @@ public class RootParallelization implements Policy {
qValues = policy.getQvalues(gameConfig, gameState, player);
}
}
@Override
public void setState(GameState gameState) {
// TODO Auto-generated method stub
}
}

View File

@@ -1,3 +1,4 @@
T__20=20
T__21=21
T__22=22
T__23=23
@@ -24,46 +25,68 @@ T__43=43
T__44=44
T__45=45
T__46=46
T__47=47
T__48=48
T__49=49
T__50=50
T__51=51
T__52=52
T__53=53
T__54=54
T__55=55
T__56=56
T__57=57
COLON=4
COMMA=5
CR=6
DIGIT=7
LBRACKET=8
LCLETTER=9
LPAREN=10
MINUS=11
NEWLINE=12
PERIOD=13
PLUS=14
RBRACKET=15
RPAREN=16
SEMICOLON=17
SLASH=18
SPACE=19
UCLETTER=20
'AB'=21
'AP'=22
'AW'=23
'B'=24
'BC'=25
'BR'=26
'CA'=27
'CP'=28
'DT'=29
'EV'=30
'FF'=31
'GM'=32
'KM'=33
'PB'=34
'PC'=35
'PW'=36
'R'=37
'RE'=38
'RU'=39
'SO'=40
'SZ'=41
'TM'=42
'US'=43
'W'=44
'WC'=45
'WR'=46
DIGIT=6
LBRACKET=7
LCLETTER=8
LPAREN=9
MINUS=10
PERIOD=11
PLUS=12
RBRACKET=13
RPAREN=14
SEMICOLON=15
SLASH=16
SPACE=17
STRVALUE=18
UCLETTER=19
'AB'=20
'AP'=21
'AW'=22
'B'=23
'BC'=24
'BR'=25
'Black'=26
'C'=27
'CA'=28
'CP'=29
'DT'=30
'DaTe'=31
'EV'=32
'EVent'=33
'FF'=34
'GM'=35
'GaMe'=36
'KM'=37
'PB'=38
'PC'=39
'PW'=40
'PlaCe'=41
'PlayerBlack'=42
'PlayerWhite'=43
'RE'=44
'REsult'=45
'RU'=46
'SO'=47
'SZ'=48
'SiZe'=49
'TM'=50
'US'=51
'VW'=52
'VieW'=53
'W'=54
'WC'=55
'WR'=56
'White'=57

View File

@@ -34,7 +34,7 @@ public class SGFGameTree {
return subTrees.size();
}
public String toLateXmoves(Player player) {
public String toLateXmoves(Player player, int boardSize) {
StringBuilder latexSB = new StringBuilder();
SGFNode.TYPE nodeType;
SGFIdentifier sgfIdent;
@@ -73,7 +73,8 @@ public class SGFGameTree {
} else {
latexSB.append(column);
}
latexSB.append(19 - sgfCoord.getRow() + 'a');
char row = sgfCoord.getRow();
latexSB.append(boardSize - row + 'a');
nMoves++;
}
if (nMoves == 0) {
@@ -83,7 +84,20 @@ public class SGFGameTree {
return latexSB.toString();
}
public String toLateX() {
public int getBoardSize() {
for (SGFNode node : nodeSequence) {
SGFNode.TYPE nodeType = node.getType();
switch (nodeType) {
case ROOT:
return Integer.valueOf(node.getFirstValue(SGFIdentifier.SIZE).getText());
default:
// ignore
}
}
throw new RuntimeException("Cannot get board size: SGFNode with identifier SZ was not found in any nodeSequence of type ROOT.");
}
public String toLateX(int boardSize) {
StringBuilder latexSB = new StringBuilder();
// Somewhat convoluted logic here because the grammar does not require
@@ -97,7 +111,7 @@ public class SGFGameTree {
case ROOT:
latexSB.append("\\gobansize");
latexSB.append("{");
latexSB.append(node.getFirstValue(SGFIdentifier.SIZE));
latexSB.append(boardSize);
latexSB.append("}\n");
latexSB.append("\\shortstack{\\showfullgoban\\\\");
SGFResult result = (SGFResult) node.getFirstValue(
@@ -120,4 +134,15 @@ public class SGFGameTree {
sgfFormatString.append(")");
return sgfFormatString.toString();
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("(");
for (SGFNode node : nodeSequence) {
stringBuilder.append(node.toString());
}
stringBuilder.append(")");
return stringBuilder.toString();
}
}

View File

@@ -3,15 +3,29 @@ package net.woodyfolsom.msproj.sgf;
public class SGFIdentifier {
public static final SGFIdentifier ADD_BLACK = new SGFIdentifier("AB");
public static final SGFIdentifier ADD_WHITE = new SGFIdentifier("AW");
public static final SGFIdentifier APPLICATION = new SGFIdentifier("AP");
public static final SGFIdentifier COUNTRY_BLACK = new SGFIdentifier("BC");
public static final SGFIdentifier COUNTRY_WHITE = new SGFIdentifier("WC");
public static final SGFIdentifier CHARSET = new SGFIdentifier("CA");
public static final SGFIdentifier COMMENT = new SGFIdentifier("C");
public static final SGFIdentifier DATE = new SGFIdentifier("DT");
public static final SGFIdentifier EVENT = new SGFIdentifier("EV");
public static final SGFIdentifier FILE_FORMAT = new SGFIdentifier("FF");
public static final SGFIdentifier GAME = new SGFIdentifier("GM");
public static final SGFIdentifier KOMI = new SGFIdentifier("KM");
public static final SGFIdentifier MOVE_BLACK = new SGFIdentifier("B");
public static final SGFIdentifier MOVE_WHITE = new SGFIdentifier("W");
public static final SGFIdentifier PLACE = new SGFIdentifier("PC");
public static final SGFIdentifier PLAYER_BLACK = new SGFIdentifier("PB");
public static final SGFIdentifier PLAYER_WHITE = new SGFIdentifier("PW");
public static final SGFIdentifier RANK_BLACK = new SGFIdentifier("RB");
public static final SGFIdentifier RANK_WHITE = new SGFIdentifier("RW");
public static final SGFIdentifier RESULT = new SGFIdentifier("RE");
public static final SGFIdentifier RULES = new SGFIdentifier("RU");
public static final SGFIdentifier SIZE = new SGFIdentifier("SZ");
public static final SGFIdentifier SOURCE = new SGFIdentifier("SO");
public static final SGFIdentifier TIME = new SGFIdentifier("TM");
public static final SGFIdentifier VIEW = new SGFIdentifier("VW");
private String text;

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@ import java.util.List;
public class SGFNode {
public enum TYPE {
ROOT, MOVE_BLACK, MOVE_WHITE, EMPTY
ROOT, MOVE_BLACK, MOVE_WHITE, EMPTY, COMMENT
}
private List<SGFProperty> properties = new ArrayList<SGFProperty>();
@@ -18,6 +18,8 @@ public class SGFNode {
type = TYPE.MOVE_BLACK;
} else if (sgfIdent == SGFIdentifier.MOVE_WHITE) {
type = TYPE.MOVE_WHITE;
} else if (sgfIdent == SGFIdentifier.COMMENT) {
type = TYPE.COMMENT;
} else {
type = TYPE.ROOT;
}
@@ -59,4 +61,14 @@ public class SGFNode {
return sgfFormatString;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(";");
for (SGFProperty property : properties) {
stringBuilder.append(property.toString());
}
return stringBuilder.toString();
}
}

View File

@@ -24,25 +24,30 @@ public class SGFNodeCollection {
StringBuilder latexFormatString = new StringBuilder("");
SGFGameTree gameTree = gameTrees.get(0);
latexFormatString.append(gameTree.toLateXmoves(Player.BLACK));
latexFormatString.append(gameTree.toLateXmoves(Player.WHITE));
int boardSize = gameTree.getBoardSize();
latexFormatString.append(gameTree.toLateXmoves(Player.BLACK, boardSize));
latexFormatString.append(gameTree.toLateXmoves(Player.WHITE, boardSize));
latexFormatString.append("\\begin{center}\n");
latexFormatString.append(gameTree.toLateX());
latexFormatString.append(gameTree.toLateX(boardSize));
latexFormatString.append("\\end{center}");
return latexFormatString.toString();
}
/**
* This method is an alias for toString().
* @return
*/
public String toSGF() {
String sgfFormatString = "";
for (SGFGameTree gameTree : gameTrees) {
sgfFormatString += gameTree.toSGF();
}
return sgfFormatString;
return toString();
}
@Override
public String toString() {
return toSGF();
StringBuilder sbuilder = new StringBuilder();
for (SGFGameTree gameTree : gameTrees) {
sbuilder.append(gameTree.toString());
}
return sbuilder.toString();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -36,4 +36,15 @@ public class SGFProperty {
return sgfFormatString;
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder(identifier.toString());
for (SGFValue<?> value : values) {
stringBuilder.append("[");
stringBuilder.append(value.toString());
stringBuilder.append("]");
}
return stringBuilder.toString();
}
}

View File

@@ -1,15 +0,0 @@
(;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])

View File

@@ -49,6 +49,7 @@ public class CollectionTest {
SGFParser parser = new SGFParser(tokens);
SGFNodeCollection nodeCollection = parser.collection();
assertEquals(TEST_LATEX, nodeCollection.toLateX());
String actualLaTeX = nodeCollection.toLateX();
assertEquals(TEST_LATEX, actualLaTeX);
}
}

View File

@@ -31,4 +31,24 @@ public class SGFParserTest {
System.out.println("");
}
@Test
public void testParse9x9() throws RecognitionException, IOException {
FileInputStream fis = new FileInputStream(new File(
"data/games/pro9x9/game001.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("");
}
}