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

View File

@@ -28,7 +28,7 @@ DaTe[1968]
PlaCe[] PlaCe[]
REsult[Black wins by four points] REsult[B+4]
C[This was the first of a two game match on 9x9, played 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) { public GameResult play(GameConfig gameConfig) {
GameState gameState = new GameState(gameConfig); GameRecord gameRecord = new GameRecord(gameConfig);
System.out.println("Game started."); System.out.println("Game started.");
try { try {
while (!gameState.isTerminal()) { while (!gameRecord.isFinished()) {
GameState gameState = gameRecord.getGameState(gameRecord.getNumTurns());
System.out.println(gameState); System.out.println(gameState);
Player currentPlayer = gameState.getPlayerToMove(); Player playerToMove = gameRecord.getPlayerToMove();
Action action = getPolicy(currentPlayer).getAction(gameConfig, Policy policy = getPolicy(playerToMove);
gameState, currentPlayer); Action action = policy.getAction(gameConfig,
gameState.playStone(currentPlayer, action); gameState, playerToMove);
if (gameRecord.play(playerToMove, action)) {
policy.setState(gameRecord.getGameState(gameRecord.getNumTurns()));
} else {
System.out.println("Move rejected - try again.");
}
} }
} catch (Exception ex) { } catch (Exception ex) {
System.out System.out
@@ -56,7 +63,7 @@ public class Referee {
return GameResult.VOID; return GameResult.VOID;
} }
GameResult result = gameState.getResult(); GameResult result = gameRecord.getResult();
System.out.println("Game over. Result: " + result); System.out.println("Game over. Result: " + result);
@@ -68,7 +75,7 @@ public class Referee {
+ ".sgf"); + ".sgf");
FileOutputStream fos = new FileOutputStream(sgfFile); FileOutputStream fos = new FileOutputStream(sgfFile);
try { try {
SGFWriter.writeSGF(gameState, fos); SGFWriter.write(fos, gameRecord);
System.out System.out
.println("Game saved as " + sgfFile.getAbsolutePath()); .println("Game saved as " + sgfFile.getAbsolutePath());
} finally { } finally {

View File

@@ -2,21 +2,45 @@ package net.woodyfolsom.msproj;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter;
import net.woodyfolsom.msproj.sgf.SGFIdentifier;
public class SGFWriter { public class SGFWriter {
public static void writeSGF(GameState gameState, OutputStream os) public static void write(OutputStream os, GameRecord gameRecord)
throws IOException { throws IOException {
writeNode(os, SGFIdentifier.FILE_FORMAT, Integer.valueOf(4)); OutputStreamWriter writer = new OutputStreamWriter(os);
}
private static void writeNode(OutputStream os, SGFIdentifier sgfIdent, writer.write("(");
Object nodeValue) throws IOException {
os.write(sgfIdent.toString().getBytes()); writer.write(";FF[4]GM[1]");
os.write("[".getBytes());
os.write(nodeValue.toString().getBytes()); GameConfig gameConfig = gameRecord.getGameConfig();
os.write("];".getBytes());
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; package net.woodyfolsom.msproj.gui;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.event.KeyEvent; import java.awt.event.ActionEvent;
import java.awt.event.KeyListener; import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JPanel;
import net.woodyfolsom.msproj.Action; import net.woodyfolsom.msproj.Action;
import net.woodyfolsom.msproj.GameConfig; import net.woodyfolsom.msproj.GameConfig;
import net.woodyfolsom.msproj.GameState; import net.woodyfolsom.msproj.GameState;
import net.woodyfolsom.msproj.Player; import net.woodyfolsom.msproj.Player;
public class Goban extends JFrame implements KeyListener { public class Goban extends JFrame {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
//private GameState gameState;
private GridPanel gridPanel; 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) { public Goban(GameConfig gameConfig, Player guiPlayer) {
setLayout(new BorderLayout()); setLayout(new BorderLayout());
this.gridPanel = new GridPanel(gameConfig, guiPlayer); this.gridPanel = new GridPanel(gameConfig, guiPlayer);
add(gridPanel,BorderLayout.CENTER); add(gridPanel,BorderLayout.CENTER);
addKeyListener(this);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true); 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(); pack();
} }
@@ -45,31 +60,4 @@ public class Goban extends JFrame implements KeyListener {
gridPanel.setGameState(gameState); 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() { public Action getAction() {
int timeLimit = 10; int timeLimit = 30;
TimeUnit timeUnit = TimeUnit.SECONDS; TimeUnit timeUnit = TimeUnit.SECONDS;
try { try {
@@ -212,6 +216,7 @@ public class GridPanel extends JPanel implements MouseListener,
public void setGameState(GameState gameState) { public void setGameState(GameState gameState) {
this.gameState = gameState; this.gameState = gameState;
this.repaint();
} }
@Override @Override

View File

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

View File

@@ -70,4 +70,10 @@ public class HumanKeyboardInput implements Policy {
return 1; 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( throw new UnsupportedOperationException(
"Prohibited actions not supported by this class."); "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; import net.woodyfolsom.msproj.tree.MonteCarloProperties;
public abstract class MonteCarlo implements Policy { 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 int numStateEvaluations = 0;
protected Policy movePolicy; protected Policy movePolicy;
@@ -113,10 +113,6 @@ public abstract class MonteCarlo implements Policy {
return searchTimeLimit; return searchTimeLimit;
} }
public int doRollout() {
return 0;
}
public int getNumStateEvaluations() { public int getNumStateEvaluations() {
return numStateEvaluations; return numStateEvaluations;
} }

View File

@@ -196,4 +196,10 @@ public class MonteCarloUCT extends MonteCarlo {
public String toString() { public String toString() {
return "MonteCarloUCT"; 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); Collection<Action> prohibitedActions, Player player);
public int getNumStateEvaluations(); public int getNumStateEvaluations();
public void setState(GameState gameState);
} }

View File

@@ -83,4 +83,10 @@ public class RandomMovePolicy implements Policy, ActionGenerator {
Player player) { Player player) {
return getActions(gameConfig, gameState, player, 1).get(0); 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); 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__21=21
T__22=22 T__22=22
T__23=23 T__23=23
@@ -24,46 +25,68 @@ T__43=43
T__44=44 T__44=44
T__45=45 T__45=45
T__46=46 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 COLON=4
COMMA=5 COMMA=5
CR=6 DIGIT=6
DIGIT=7 LBRACKET=7
LBRACKET=8 LCLETTER=8
LCLETTER=9 LPAREN=9
LPAREN=10 MINUS=10
MINUS=11 PERIOD=11
NEWLINE=12 PLUS=12
PERIOD=13 RBRACKET=13
PLUS=14 RPAREN=14
RBRACKET=15 SEMICOLON=15
RPAREN=16 SLASH=16
SEMICOLON=17 SPACE=17
SLASH=18 STRVALUE=18
SPACE=19 UCLETTER=19
UCLETTER=20 'AB'=20
'AB'=21 'AP'=21
'AP'=22 'AW'=22
'AW'=23 'B'=23
'B'=24 'BC'=24
'BC'=25 'BR'=25
'BR'=26 'Black'=26
'CA'=27 'C'=27
'CP'=28 'CA'=28
'DT'=29 'CP'=29
'EV'=30 'DT'=30
'FF'=31 'DaTe'=31
'GM'=32 'EV'=32
'KM'=33 'EVent'=33
'PB'=34 'FF'=34
'PC'=35 'GM'=35
'PW'=36 'GaMe'=36
'R'=37 'KM'=37
'RE'=38 'PB'=38
'RU'=39 'PC'=39
'SO'=40 'PW'=40
'SZ'=41 'PlaCe'=41
'TM'=42 'PlayerBlack'=42
'US'=43 'PlayerWhite'=43
'W'=44 'RE'=44
'WC'=45 'REsult'=45
'WR'=46 '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(); return subTrees.size();
} }
public String toLateXmoves(Player player) { public String toLateXmoves(Player player, int boardSize) {
StringBuilder latexSB = new StringBuilder(); StringBuilder latexSB = new StringBuilder();
SGFNode.TYPE nodeType; SGFNode.TYPE nodeType;
SGFIdentifier sgfIdent; SGFIdentifier sgfIdent;
@@ -73,7 +73,8 @@ public class SGFGameTree {
} else { } else {
latexSB.append(column); latexSB.append(column);
} }
latexSB.append(19 - sgfCoord.getRow() + 'a'); char row = sgfCoord.getRow();
latexSB.append(boardSize - row + 'a');
nMoves++; nMoves++;
} }
if (nMoves == 0) { if (nMoves == 0) {
@@ -83,7 +84,20 @@ public class SGFGameTree {
return latexSB.toString(); 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(); StringBuilder latexSB = new StringBuilder();
// Somewhat convoluted logic here because the grammar does not require // Somewhat convoluted logic here because the grammar does not require
@@ -97,7 +111,7 @@ public class SGFGameTree {
case ROOT: case ROOT:
latexSB.append("\\gobansize"); latexSB.append("\\gobansize");
latexSB.append("{"); latexSB.append("{");
latexSB.append(node.getFirstValue(SGFIdentifier.SIZE)); latexSB.append(boardSize);
latexSB.append("}\n"); latexSB.append("}\n");
latexSB.append("\\shortstack{\\showfullgoban\\\\"); latexSB.append("\\shortstack{\\showfullgoban\\\\");
SGFResult result = (SGFResult) node.getFirstValue( SGFResult result = (SGFResult) node.getFirstValue(
@@ -120,4 +134,15 @@ public class SGFGameTree {
sgfFormatString.append(")"); sgfFormatString.append(")");
return sgfFormatString.toString(); 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 class SGFIdentifier {
public static final SGFIdentifier ADD_BLACK = new SGFIdentifier("AB"); public static final SGFIdentifier ADD_BLACK = new SGFIdentifier("AB");
public static final SGFIdentifier ADD_WHITE = new SGFIdentifier("AW"); 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 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 FILE_FORMAT = new SGFIdentifier("FF");
public static final SGFIdentifier GAME = new SGFIdentifier("GM"); public static final SGFIdentifier GAME = new SGFIdentifier("GM");
public static final SGFIdentifier KOMI = new SGFIdentifier("KM"); public static final SGFIdentifier KOMI = new SGFIdentifier("KM");
public static final SGFIdentifier MOVE_BLACK = new SGFIdentifier("B"); public static final SGFIdentifier MOVE_BLACK = new SGFIdentifier("B");
public static final SGFIdentifier MOVE_WHITE = new SGFIdentifier("W"); 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 RESULT = new SGFIdentifier("RE");
public static final SGFIdentifier RULES = new SGFIdentifier("RU");
public static final SGFIdentifier SIZE = new SGFIdentifier("SZ"); 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 TIME = new SGFIdentifier("TM");
public static final SGFIdentifier VIEW = new SGFIdentifier("VW");
private String text; 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 class SGFNode {
public enum TYPE { public enum TYPE {
ROOT, MOVE_BLACK, MOVE_WHITE, EMPTY ROOT, MOVE_BLACK, MOVE_WHITE, EMPTY, COMMENT
} }
private List<SGFProperty> properties = new ArrayList<SGFProperty>(); private List<SGFProperty> properties = new ArrayList<SGFProperty>();
@@ -18,6 +18,8 @@ public class SGFNode {
type = TYPE.MOVE_BLACK; type = TYPE.MOVE_BLACK;
} else if (sgfIdent == SGFIdentifier.MOVE_WHITE) { } else if (sgfIdent == SGFIdentifier.MOVE_WHITE) {
type = TYPE.MOVE_WHITE; type = TYPE.MOVE_WHITE;
} else if (sgfIdent == SGFIdentifier.COMMENT) {
type = TYPE.COMMENT;
} else { } else {
type = TYPE.ROOT; type = TYPE.ROOT;
} }
@@ -59,4 +61,14 @@ public class SGFNode {
return sgfFormatString; 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(""); StringBuilder latexFormatString = new StringBuilder("");
SGFGameTree gameTree = gameTrees.get(0); SGFGameTree gameTree = gameTrees.get(0);
latexFormatString.append(gameTree.toLateXmoves(Player.BLACK)); int boardSize = gameTree.getBoardSize();
latexFormatString.append(gameTree.toLateXmoves(Player.WHITE)); latexFormatString.append(gameTree.toLateXmoves(Player.BLACK, boardSize));
latexFormatString.append(gameTree.toLateXmoves(Player.WHITE, boardSize));
latexFormatString.append("\\begin{center}\n"); latexFormatString.append("\\begin{center}\n");
latexFormatString.append(gameTree.toLateX()); latexFormatString.append(gameTree.toLateX(boardSize));
latexFormatString.append("\\end{center}"); latexFormatString.append("\\end{center}");
return latexFormatString.toString(); return latexFormatString.toString();
} }
/**
* This method is an alias for toString().
* @return
*/
public String toSGF() { public String toSGF() {
String sgfFormatString = ""; return toString();
for (SGFGameTree gameTree : gameTrees) {
sgfFormatString += gameTree.toSGF();
}
return sgfFormatString;
} }
@Override @Override
public String toString() { 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; 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); SGFParser parser = new SGFParser(tokens);
SGFNodeCollection nodeCollection = parser.collection(); 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(""); 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("");
}
} }