// Analyze.java
package net.sf.gogui.tools.statistics;
import java.awt.Color;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.text.DecimalFormat;
import static net.sf.gogui.go.GoColor.BLACK;
import static net.sf.gogui.go.GoColor.WHITE;
import net.sf.gogui.game.GameInfo;
import net.sf.gogui.game.GameTree;
import net.sf.gogui.game.StringInfo;
import net.sf.gogui.game.StringInfoColor;
import net.sf.gogui.sgf.SgfReader;
import net.sf.gogui.util.ErrorMessage;
import net.sf.gogui.util.FileUtil;
import net.sf.gogui.util.Histogram;
import net.sf.gogui.util.HtmlUtil;
import net.sf.gogui.util.StringUtil;
import net.sf.gogui.util.Table;
import net.sf.gogui.util.TableUtil;
/** Produce HTML reports from the table generated by Statistics. */
public class Analyze
{
public Analyze(String fileName, String output, int precision)
throws Exception
{
if (output.equals(""))
m_output = FileUtil.removeExtension(new File(fileName), "dat");
else if (new File(output).isDirectory())
{
File name = new File((new File(fileName)).getName());
m_output = output + File.separator
+ FileUtil.removeExtension(name, "dat");
}
else
m_output = output;
m_precision = precision;
m_table = new Table();
m_table.read(new File(fileName));
if (m_table.getNumberColumns() < 2
|| ! m_table.getColumnTitle(0).equals("File")
|| ! m_table.getColumnTitle(1).equals("Move"))
throw new ErrorMessage("Invalid table format");
m_commands = new ArrayList<String>();
for (int i = 2; i < m_table.getNumberColumns(); ++i)
m_commands.add(m_table.getColumnTitle(i));
m_commandStatistics =
new ArrayList<CommandStatistics>(m_commands.size());
File file = new File(m_output + ".html");
initGameData();
findGameGlobalCommands();
PrintStream out = new PrintStream(file);
startHtml(out, "Statistics Summary");
startInfo(out, "Statistics Summary");
writeInfo(out);
endInfo(out);
out.print("<table border=\"0\">\n" +
"<tr><td>\n");
writePlot(out, "<small>positions</small>",
getCountFile().getName(),
"<a href=\"" + getCountDataFile().getName()
+ "\"><small>data</small></a>");
out.print("</td></tr>\n");
for (int i = 0; i < m_commands.size(); ++i)
{
CommandStatistics commandStatistics = computeCommandStatistics(i);
m_commandStatistics.add(commandStatistics);
if (commandStatistics.getCount() > 0
&& ! commandStatistics.m_isBeginCommand)
{
String command = getCommand(i);
Table table = commandStatistics.m_tableAtMove;
Plot plot = generatePlotMove(getImgWidth(m_maxMove),
getColor(command));
plot.setFormatY(commandStatistics.m_format);
File pngFile = getAvgPlotFile(i);
File dataFile = getAvgDataFile(i);
plot.setPlotStyleNoLines();
plot.plot(pngFile, table, "Move", "Mean", "Error");
FileWriter writer = new FileWriter(dataFile);
try
{
table.save(writer, false);
}
finally
{
writer.close();
}
out.print("<tr><td>\n");
writePlot(out, getCommandLink(i), pngFile.getName(),
"<a href=\"" + dataFile.getName()
+ "\"><small>data</small></a>");
out.print("</td></tr>\n");
}
}
out.print("</table>\n" +
"<hr>\n" +
"<table border=\"0\" cellpadding=\"0\">\n" +
"<tr>\n");
int n = 0;
for (int i = 0; i < m_commands.size(); ++i)
{
CommandStatistics commandStatistics = getCommandStatistics(i);
if (commandStatistics.getCount() == 0)
continue;
out.print("<td valign=\"bottom\" bgcolor=\"" + COLOR_HEADER
+ "\">\n");
writePlot(out, getCommandLink(i), getHistoFile(i).getName(), "");
out.print("</td>\n");
++n;
if (n % 5 == 0)
out.print("</tr><tr>\n");
}
out.print("</tr>\n" +
"</table>\n" +
"<hr>\n");
writeCommandsTable(out);
out.print("<hr>\n");
writeGameTable(out);
finishHtml(out);
out.close();
}
private static final Color[] PLOT_COLOR = {
Color.decode("#ff0000"),
Color.decode("#ff9800"),
Color.decode("#009800"),
Color.decode("#00c0c0"),
Color.decode("#0000ff"),
Color.decode("#980098")
};
/** Command having at most one result per game. */
private static class GameGlobalCommand
{
public GameGlobalCommand(String name, ArrayList<String> results)
{
m_name = name;
m_results = results;
initAllEmpty();
}
public boolean allEmpty()
{
return m_allEmpty;
}
public String getName()
{
return m_name;
}
public String getResult(int game)
{
return m_results.get(game);
}
private boolean m_allEmpty;
private final String m_name;
/** Results per game. */
private final ArrayList<String> m_results;
private void initAllEmpty()
{
m_allEmpty = false;
for (int game = 0; game < m_results.size(); ++game)
{
String result = getResult(game);
if (! StringUtil.isEmpty(result))
return;
}
m_allEmpty = true;
}
}
private static class GameData
{
public String m_file;
public String m_name;
public int m_finalPosition;
public int m_numberPositions;
}
private static final int IMAGE_HEIGHT = 100;
private int m_maxMove;
private int m_movePrintInterval;
private final int m_precision;
private static final String COLOR_HEADER = "#b5c8f0";
private static final String COLOR_INFO = "#e0e0e0";
private final String m_output;
private final Table m_table;
private Table m_tableFinal;
private final ArrayList<CommandStatistics> m_commandStatistics;
private final ArrayList<String> m_commands;
private ArrayList<GameGlobalCommand> m_gameGlobalCommands;
private ArrayList<GameData> m_gameData;
private void endInfo(PrintStream out)
{
out.print("</table></td></tr>\n" +
"</table>\n" +
"<hr>\n");
}
private void findGameGlobalCommands() throws Table.InvalidLocation
{
m_gameGlobalCommands = new ArrayList<GameGlobalCommand>();
for (int i = 0; i < m_commands.size(); ++i)
{
String command = getCommand(i);
boolean isGameGlobal = true;
ArrayList<String> gameResult = new ArrayList<String>();
for (int j = 0; j < m_gameData.size(); ++j)
{
GameData data = m_gameData.get(j);
Table table = TableUtil.select(m_table, "File", data.m_file,
command);
ArrayList<String> notEmpty
= TableUtil.getColumnNotEmpty(table, command);
if (notEmpty.size() > 1)
{
isGameGlobal = false;
break;
}
else if (notEmpty.size() == 1)
gameResult.add(notEmpty.get(0));
else
gameResult.add("");
}
if (isGameGlobal)
{
GameGlobalCommand gameGlobalCommand
= new GameGlobalCommand(command, gameResult);
m_gameGlobalCommands.add(gameGlobalCommand);
}
}
}
private void finishHtml(PrintStream out)
{
out.print(HtmlUtil.getFooter("gogui-statistics") +
"</body>\n" +
"</html>\n");
}
private File getAvgDataFile(int commandIndex)
{
return new File(m_output + ".command-" + commandIndex + ".avg.dat");
}
private File getAvgPlotFile(int commandIndex)
{
return new File(m_output + ".command-" + commandIndex + ".avg.png");
}
private String getCommand(int index)
{
return m_commands.get(index);
}
private File getCommandFile(int commandIndex)
{
return new File(m_output + ".command-" + commandIndex + ".html");
}
private CommandStatistics getCommandStatistics(int commandIndex)
{
return m_commandStatistics.get(commandIndex);
}
private File getCountFile()
{
return new File(m_output + ".count.png");
}
private File getCountDataFile()
{
return new File(m_output + ".count.dat");
}
private File getGameFile(int gameIndex)
{
return new File(m_output + ".game-" + gameIndex + ".html");
}
private GameGlobalCommand getGameGlobalCommand(int index)
{
return m_gameGlobalCommands.get(index);
}
private File getHistoFile(int commandIndex)
{
return new File(m_output + ".command-" + commandIndex + ".histo.png");
}
private File getHistoFile(int commandIndex, int moveIntervalIndex)
{
return new File(m_output + ".command-" + commandIndex + ".interval-"
+ moveIntervalIndex + ".histo.png");
}
private File getHistoFinalFile(int commandIndex)
{
return new File(m_output + ".command-" + commandIndex + ".final.png");
}
private File getPlotFile(int gameIndex, int commandIndex)
{
return new File(m_output + ".game-" + gameIndex + ".command-"
+ commandIndex + ".png");
}
private String getCommandLink(int commandIndex)
{
String link = "<small>" + getCommand(commandIndex) + "</small>";
CommandStatistics statistics = getCommandStatistics(commandIndex);
if (statistics.getCount() == 0 || statistics.m_isBeginCommand)
return link;
return "<a href=\"" + getCommandFile(commandIndex).getName()
+ "\">" + link + "</a>";
}
private CommandStatistics computeCommandStatistics(int index)
throws Exception
{
String command = getCommand(index);
return new CommandStatistics(command, m_table, m_tableFinal,
getHistoFile(index),
getHistoFinalFile(index),
getColor(command), m_precision);
}
private Plot generatePlotMove(int width, Color color)
{
Plot plot = new Plot(width, IMAGE_HEIGHT, color, m_precision);
plot.setSolidLineInterval(10);
plot.setXMin(0);
plot.setXMax(m_maxMove);
plot.setXTics(5);
plot.setXLabelPerTic(2);
return plot;
}
private void generatePlot(int commandIndex, DecimalFormat format,
int gameIndex, String gameFile) throws Exception
{
String command = getCommand(commandIndex);
Table table = TableUtil.select(m_table, "File", gameFile,
"Move", command);
File file = getPlotFile(gameIndex, commandIndex);
Plot plot = generatePlotMove(getImgWidth(m_maxMove),
getColor(command));
plot.setFormatY(format);
plot.plot(file, table, "Move", command, null);
}
private Color getColor(String command) throws Table.InvalidLocation
{
int index = m_table.getColumnIndex(command);
return PLOT_COLOR[(index - 2) % PLOT_COLOR.length];
}
private String getGameLink(File fromFile, int gameNumber,
boolean shortName)
{
GameData data = m_gameData.get(gameNumber);
File gameFile = new File(data.m_file);
if (! gameFile.exists())
return (shortName ? gameFile.getName() : gameFile.toString());
String path = FileUtil.getRelativeURI(fromFile, gameFile);
return "<a href=\"" + path + "\">"
+ (shortName ? gameFile.getName() : path) + "</a>";
}
private int getImgWidth(int numberMoves)
{
return Math.max(10, Math.min(numberMoves * 9, 1040));
}
private void initGameData() throws Table.InvalidLocation, IOException
{
m_gameData = new ArrayList<GameData>();
String last = null;
GameData data = null;
m_maxMove = 0;
int[] count = new int[0];
for (int row = 0; row < m_table.getNumberRows(); ++row)
{
String file = m_table.get("File", row);
int move = Integer.parseInt(m_table.get("Move", row));
if (move >= count.length)
{
int[] newCount = new int[move + 1];
for (int i = 0; i < count.length; ++i)
newCount[i] = count[i];
count = newCount;
}
++count[move];
m_maxMove = Math.max(m_maxMove, move);
if (last == null || ! file.equals(last))
{
if (data != null)
m_gameData.add(data);
data = new GameData();
data.m_file = file;
data.m_name = new File(file).getName();
}
++data.m_numberPositions;
data.m_finalPosition = move;
last = file;
}
m_movePrintInterval = 1;
while (m_movePrintInterval < m_maxMove / 30)
{
m_movePrintInterval *= 5;
if (m_movePrintInterval >= m_maxMove / 30)
break;
m_movePrintInterval *= 2;
}
m_gameData.add(data);
m_tableFinal = new Table(m_table.getColumnTitles());
for (int i = 0; i < m_gameData.size(); ++i)
{
data = m_gameData.get(i);
String file = data.m_file;
String finalPosition = Integer.toString(data.m_finalPosition);
int row = TableUtil.findRow(m_table, "File", file, "Move",
finalPosition);
TableUtil.appendRow(m_tableFinal, m_table, row);
}
ArrayList<String> columnTitles = new ArrayList<String>();
columnTitles.add("Move");
columnTitles.add("Count");
Table table = new Table(columnTitles);
for (int i = 0; i < count.length; ++i)
{
if (count[i] == 0)
continue;
table.startRow();
table.set("Move", i);
table.set("Count", count[i]);
}
Plot plot = generatePlotMove(getImgWidth(m_maxMove), Color.DARK_GRAY);
plot.setNoPlotYZero();
plot.plot(getCountFile(), table, "Move", "Count", null);
FileWriter writer = new FileWriter(getCountDataFile());
try
{
table.save(writer, false);
}
finally
{
writer.close();
}
}
private boolean isGameGlobalCommand(String command)
{
for (int i = 0; i < m_gameGlobalCommands.size(); ++i)
if (getGameGlobalCommand(i).getName().equals(command))
return true;
return false;
}
private void startHtml(PrintStream out, String title)
{
String charset = StringUtil.getDefaultEncoding();
out.print("<html>\n" +
"<head>\n" +
"<title>" + title + "</title>\n" +
"<meta http-equiv=\"Content-Type\""
+ " content=\"text/html; charset=" + charset + "\">\n" +
HtmlUtil.getMeta("gogui-statistics") +
"<style type=\"text/css\">\n" +
"<!--\n" +
"a:link { color:#0000ee }\n" +
"a:visited { color:#551a8b }\n" +
".smalltable { font-size:80%; }\n" +
".smalltable td { background-color:" + COLOR_INFO
+ "; text-align:center; }\n" +
".smalltable th { background-color:" + COLOR_HEADER
+ "; vertical-align:top; }\n" +
".smalltable table { border:0; cellpadding:0; }\n" +
"-->\n" +
"</style>\n" +
"</head>\n" +
"<body bgcolor=\"white\" text=\"black\">\n");
}
private void startInfo(PrintStream out, String title)
{
out.print("<table border=\"0\" width=\"100%\" bgcolor=\""
+ COLOR_HEADER + "\">\n" +
"<tr><td>\n" +
"<h1>" + title + "</h1>\n" +
"</td></tr>\n" +
"</table>\n" +
"<table width=\"100%\" bgcolor=\"" + COLOR_INFO
+ "\" >\n" +
"<tr><td><table style=\"font-size:80%\""
+ " cellpadding=\"0\">\n");
}
private void writeCommandPage(int commandIndex)
throws Exception
{
String command = getCommand(commandIndex);
CommandStatistics commandStatistics
= getCommandStatistics(commandIndex);
File file = getCommandFile(commandIndex);
PrintStream out = new PrintStream(file);
startHtml(out, command);
startInfo(out, command);
writeInfoBasics(out);
writeHtmlRow(out, "Command Index", commandIndex);
endInfo(out);
if (! commandStatistics.m_isBeginCommand)
out.print("<p><img src=\""
+ getAvgPlotFile(commandIndex).getName()
+ "\"></p>\n");
writeCommandStatistics(out, commandIndex);
out.print("<hr>\n");
out.print("<table border=\"0\" cellspacing=\"0\""
+ " cellpadding=\"5\">\n");
out.print("<tr><td>"
+ "<small>All</small><br>"
+ "<img src=\"" + getHistoFile(commandIndex).getName()
+ "\"></td>\n");
if (commandStatistics.m_statisticsFinal.getCount() > 0)
out.print("<td>"
+ "<small>Final</small><br>"
+ "<img src=\""
+ getHistoFinalFile(commandIndex).getName()
+ "\"></td>");
out.print("</tr>\n" +
"</table>\n");
for (int i = 0; i < m_maxMove; i += m_movePrintInterval)
{
Histogram histogram
= commandStatistics.getStatistics(i).m_histogram;
if (commandStatistics.getStatistics(i).getCount() == 0)
continue;
Table histoTable
= TableUtil.fromHistogram(histogram, command);
File histoFile = getHistoFile(commandIndex, i);
Color color = getColor(command);
Plot plot = new Plot(180, 135, color, m_precision);
commandStatistics.setHistogramProperties(plot);
plot.plot(histoFile, histoTable, command, "Count", null);
out.print("<table align=\"left\" border=\"0\">" +
"<tr><td align=\"center\"><small>" + i
+ "</small><br><img src=\""
+ getHistoFile(commandIndex, i).getName()
+ "\"></td></tr></table>\n");
}
out.print("<br clear=\"left\">\n" +
"<hr>\n");
writeGamePlots(out, commandIndex);
finishHtml(out);
out.close();
}
private void writeCommandStatistics(PrintStream out, int commandIndex)
throws Exception
{
CommandStatistics commandStatistics
= getCommandStatistics(commandIndex);
String command = getCommand(commandIndex);
PositionStatistics statisticsAll = commandStatistics.m_statisticsAll;
PositionStatistics finalStatistics
= commandStatistics.m_statisticsFinal;
out.print("<table class=\"smalltable\">\n");
out.print("<tr>");
out.print("<th>Move</th>");
writeStatisticsTableHeader(out);
out.print("</tr>\n");
DecimalFormat format = commandStatistics.m_format;
for (int i = 0; i < m_maxMove; i += m_movePrintInterval)
{
PositionStatistics statisticsAtMove
= commandStatistics.getStatistics(i);
out.print("<tr>" +
"<td>" + i + "</td>");
writeStatisticsTableData(out, statisticsAtMove, format, false);
out.print("</tr>\n");
}
out.print("<tr style=\"font-weight:bold\">" +
"<td>Final</td>");
writeStatisticsTableData(out, finalStatistics, format, false);
out.print("</tr>\n");
out.print("<tr style=\"font-weight:bold\">" +
"<td>All</td>");
writeStatisticsTableData(out, statisticsAll, format,
! isGameGlobalCommand(command));
out.print("</tr>\n");
out.print("</table>\n");
}
private void writeCommandsTable(PrintStream out) throws Exception
{
out.print("<table class=\"smalltable\">\n" +
"<thead><tr>"
+ "<th>Command</th>");
writeStatisticsTableHeader(out);
out.print("</tr></thead>\n");
for (int i = 0; i < m_commands.size(); ++i)
{
CommandStatistics commandStatistics = getCommandStatistics(i);
int count = commandStatistics.getCount();
if (count > 0 && ! commandStatistics.m_isBeginCommand)
writeCommandPage(i);
PositionStatistics statisticsAll
= commandStatistics.m_statisticsAll;
out.print("<tr><td style=\"background-color:" + COLOR_HEADER
+ "\">" + getCommandLink(i) + "</td>");
writeStatisticsTableData(out, statisticsAll,
commandStatistics.m_format,
! isGameGlobalCommand(getCommand(i)));
out.print("</tr>\n");
}
out.print("</table>\n");
}
private void writeGamePage(String game, String name, int gameNumber)
throws Exception
{
File file = getGameFile(gameNumber);
PrintStream out = new PrintStream(file);
String title = "Game " + (gameNumber + 1) + " (" + name + ")";
startHtml(out, title);
startInfo(out, title);
writeInfoBasics(out);
writeHtmlRow(out, "Game Index", gameNumber);
writeHtmlRow(out, "File", getGameLink(file, gameNumber, false));
try
{
InputStream in = new FileInputStream(new File(game));
SgfReader reader = new SgfReader(in, new File(game), null, 0);
GameTree tree = reader.getTree();
GameInfo info = tree.getGameInfo(tree.getRoot());
String playerBlack = info.get(StringInfoColor.NAME, BLACK);
if (playerBlack == null)
playerBlack = "?";
String playerWhite = info.get(StringInfoColor.NAME, WHITE);
if (playerWhite == null)
playerWhite = "?";
String result = info.get(StringInfo.RESULT);
if (result == null)
result = "?";
writeHtmlRow(out, "Black", playerBlack);
writeHtmlRow(out, "White", playerWhite);
writeHtmlRow(out, "Result", result);
in.close();
}
catch (Exception e)
{
StringUtil.printException(e);
}
endInfo(out);
out.print("<table border=\"0\">\n");
for (int i = 0; i < m_commands.size(); ++i)
{
CommandStatistics commandStatistics = getCommandStatistics(i);
if (commandStatistics.getCount() > 0
&& ! commandStatistics.m_isBeginCommand)
{
generatePlot(i, commandStatistics.m_format, gameNumber, game);
out.print("<tr><td align=\"center\">" + getCommandLink(i)
+ "<br><img src=\""
+ getPlotFile(gameNumber, i).getName()
+ "\"></td></tr>\n");
}
}
out.print("</table>\n" +
"<hr>\n");
Table table = TableUtil.select(m_table, "File", game);
out.print("<table class=\"smalltable\">\n" +
"<thead><tr>");
for (int i = 1; i < table.getNumberColumns(); ++i)
{
String command = table.getColumnTitle(i);
if (! TableUtil.allEmpty(table, command))
out.print("<th>" + command + "</th>");
}
out.print("</tr></thead>\n");
for (int i = 0; i < table.getNumberRows(); ++i)
{
out.print("<tr>");
for (int j = 1; j < table.getNumberColumns(); ++j)
{
String command = table.getColumnTitle(j);
if (TableUtil.allEmpty(table, command))
continue;
String value = table.get(command, i);
if (value == null)
value = "";
out.print("<td>" + value + "</td>");
}
out.print("</tr>\n");
}
out.print("</table>\n");
finishHtml(out);
out.close();
}
private void writeGamePlots(PrintStream out, int commandIndex)
throws Exception
{
out.print("<table border=\"0\" cellpadding=\"0\""
+ " cellspacing=\"0\">\n");
for (int i = 0; i < m_gameData.size(); ++i)
{
String plotFile = getPlotFile(i, commandIndex).getName();
File file = getGameFile(i);
out.print("<tr><td align=\"left\"><small><a href=\""
+ file.getName() + "\">Game " + (i + 1) + "</a> ("
+ getGameLink(file, i, true)
+ "):</small><br>\n" +
"<img src=\"" + plotFile + "\"></td></tr>\n");
}
out.print("</table>\n");
}
private void writeGameTable(PrintStream out)
throws Exception
{
out.print("<table class=\"smalltable\">\n" +
"<thead><tr><th>Game</th><th>File</th><th>Positions</th>");
for (int i = 0; i < m_gameGlobalCommands.size(); ++i)
if (! getGameGlobalCommand(i).allEmpty())
out.print("<th>" + getGameGlobalCommand(i).m_name + "</th>");
out.print("</tr></thead>\n");
for (int i = 0; i < m_gameData.size(); ++i)
{
GameData data = m_gameData.get(i);
String file = getGameFile(i).getName();
out.print("<tr><td style=\"background-color:" + COLOR_HEADER
+ "\"><a href=\"" + file + "\">Game " + (i + 1)
+ "</a></td><td>" + data.m_name
+ "</td><td>" + data.m_numberPositions + "</td>");
for (int j = 0; j < m_gameGlobalCommands.size(); ++j)
if (! getGameGlobalCommand(j).allEmpty())
out.print("<td>" + getGameGlobalCommand(j).getResult(i)
+ "</td>");
out.print("</tr>\n");
writeGamePage(data.m_file, data.m_name, i);
}
out.print("</table>\n");
}
private void writeHtmlRow(PrintStream out, String label,
String value) throws Exception
{
out.print("<tr><th align=\"left\">" + label + ":</th>"
+ "<td align=\"left\">" + value + "</td></tr>\n");
}
private void writeHtmlRow(PrintStream out, String label,
int value) throws Exception
{
writeHtmlRow(out, label, Integer.toString(value));
}
private void writeInfoBasics(PrintStream out) throws Exception
{
writeTableProperty(out, "Name");
writeTableProperty(out, "Version");
writeTableProperty(out, "Date");
writeTableProperty(out, "Host");
writeTableProperty(out, "Program");
}
private void writeInfo(PrintStream out) throws Exception
{
writeInfoBasics(out);
writeTableProperty(out, "Size");
writeTableProperty(out, "Games");
writeHtmlRow(out, "Positions", m_table.getNumberRows());
writeTableProperty(out, "Backward");
}
private void writePlot(PrintStream out, String title, String file,
String info)
{
out.print("<table width=\"100%\" cellspacing=\"0\""
+ " cellpadding=\"0\">\n" +
"<tr><td><table width=\"100%\" border=\"0\""
+ " cellpadding=\"0\" bgcolor=\"" + COLOR_HEADER
+ "\">\n" +
"<tr><td");
if (! info.equals(""))
out.print(" width=\"90%\"");
out.print(" align=\"center\">\n" +
title + "\n" +
"</td>");
if (! info.equals(""))
out.print("<td align=\"right\">\n" + info + "\n</td>");
out.print("</tr></table></td></tr>\n" +
"<tr><td bgcolor=\"" + COLOR_INFO
+ "\">\n" +
"<img src=\"" + file + "\"></td></tr>\n" +
"</table>\n");
}
private void writeStatisticsTableData(PrintStream out,
PositionStatistics statistics,
DecimalFormat format,
boolean withMaxError)
{
boolean empty = (statistics.getCount() == 0);
boolean greaterOne = (statistics.getCount() > 1);
out.print("<td>");
if (! empty)
out.print(format.format(statistics.getMean()));
out.print("</td><td>");
if (greaterOne)
out.print(format.format(statistics.getDeviation()));
else if (! empty)
out.print("");
out.print("</td><td>");
if (greaterOne)
out.print(format.format(statistics.getError()));
else if (! empty)
out.print("");
out.print("</td><td>");
if (greaterOne && withMaxError)
{
int movesPerGame = m_table.getNumberRows() / m_gameData.size();
out.print(format.format(statistics.getMaxError(movesPerGame)));
}
else if (! empty)
out.print("");
out.print("</td><td>");
if (greaterOne)
out.print(format.format(statistics.getMin()));
else if (! empty)
out.print("");
out.print("</td><td>");
if (greaterOne)
out.print(format.format(statistics.getMax()));
else if (! empty)
out.print("");
out.print("</td><td>");
if (greaterOne)
out.print(format.format(statistics.getSum()));
else if (! empty)
out.print("");
out.print("</td><td>");
out.print(statistics.getCount());
out.print("</td><td>");
out.print(statistics.m_numberNoResult);
out.print("</td>");
}
private void writeStatisticsTableHeader(PrintStream out)
{
out.print("<th>Mean</th>"
+ "<th>Deviation</th>"
+ "<th>Error</th>"
+ "<th>MaxError</th>"
+ "<th>Min</th>"
+ "<th>Max</th>"
+ "<th>Sum</th>"
+ "<th>Count</th>"
+ "<th>Unknown</th>");
}
private void writeTableProperty(PrintStream out, String key)
throws Exception
{
writeHtmlRow(out, key, m_table.getProperty(key, "?"));
}
}