Skip to content

Commit

Permalink
Merge pull request #8 from dykstrom/feature/java11
Browse files Browse the repository at this point in the history
Feature/java11
  • Loading branch information
dykstrom authored Dec 12, 2018
2 parents 6e53e89 + e91625b commit a316d83
Show file tree
Hide file tree
Showing 25 changed files with 2,026 additions and 262 deletions.
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
language: java
jdk:
- oraclejdk8
script: "mvn verify"
- openjdk11
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,14 @@ An XBoard/WinBoard chess engine written in Java.
Ronja is a chess engine. It provides only a simple, character based user
interface. It is highly recommended that you run it from a chess GUI like
[XBoard/WinBoard](https://www.gnu.org/software/xboard) or
[Arena](http://www.playwitharena.com). You will also need
Java 8 installed to run Ronja. The Java runtime can be downloaded
from [Oracle](https://java.com/download).
[Arena](http://www.playwitharena.com). You will also need a Java runtime
installed to run Ronja.

Ronja version 0.7.0 and earlier requires Java 8; download it
[here](https://java.com/download).

Ronja version 0.8.0 and later requires Java 11; download it
[here](https://jdk.java.net/11).

## Installation

Expand Down
34 changes: 26 additions & 8 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

<groupId>se.dykstrom.ronja</groupId>
<artifactId>ronja</artifactId>
<version>0.7.1-SNAPSHOT</version>
<version>0.8.0-SNAPSHOT</version>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand All @@ -21,16 +21,16 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
Expand All @@ -43,15 +43,15 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
<version>2.22.1</version>
<configuration>
<argLine>-Djava.util.logging.config.class=se.dykstrom.ronja.test.LoggingConfig</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.20.1</version>
<version>2.22.0</version>
<configuration>
<argLine>-Djava.util.logging.config.class=se.dykstrom.ronja.test.LoggingConfig</argLine>
</configuration>
Expand Down Expand Up @@ -109,6 +109,24 @@
</build>

<dependencies>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand All @@ -124,7 +142,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
Expand Down
17 changes: 16 additions & 1 deletion src/main/java/se/dykstrom/ronja/common/book/BookMove.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

package se.dykstrom.ronja.common.book;

import java.util.Objects;

/**
* Represents an opening book move with the actual move, and its weight in the opening book.
*
Expand All @@ -34,7 +36,7 @@ public BookMove(int move, int weight) {

@Override
public String toString() {
return Integer.toString(move);
return move + "/" + weight;
}

public int getMove() {
Expand All @@ -54,4 +56,17 @@ public int getWeight() {
public BookMove withWeight(int weight) {
return new BookMove(move, weight);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BookMove that = (BookMove) o;
return this.move == that.move && this.weight == that.weight;
}

@Override
public int hashCode() {
return Objects.hash(move, weight);
}
}
152 changes: 62 additions & 90 deletions src/main/java/se/dykstrom/ronja/common/book/OpeningBookParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,83 +17,55 @@

package se.dykstrom.ronja.common.book;

import static java.util.stream.Collectors.toSet;
import se.dykstrom.ronja.common.model.Position;
import se.dykstrom.ronja.common.parser.IllegalMoveException;
import se.dykstrom.ronja.common.parser.MoveParser;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.text.ParseException;
import java.util.*;
import java.util.logging.Logger;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;

import se.dykstrom.ronja.common.model.Position;
import se.dykstrom.ronja.common.parser.IllegalMoveException;
import se.dykstrom.ronja.common.parser.MoveParser;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;

/**
* A class for parsing the Ronja opening book file. The opening book file should
* be an XML file containing a tree of 'move' elements that represent the moves
* in the different opening lines. The moves are specified in coordinate
* algebraic notation, and are associated with a weight. A move with weight 0
* will never be played, but it can still have sub moves in the opening line
* tree. This is an example of an opening book file:
*
* <?xml version="1.0" encoding="ISO-8859-1"?>
*
* <move can="" weight="">
* <move can="e2e4" weight="100" name="King's Pawn Opening">
* <move can="e7e5" weight="100">
* <move can="g1f3" weight="100"/>
* </move>
* <move can="e7e6" weight="100">
* <move can="d2d4" weight="100"/>
* </move>
* </move>
* </move>
* A class for parsing the Ronja opening book file. The opening book file is a CSV file
* containing one line for each opening line. Each line contains three fields separated
* by semicolons: a number of moves leading to a position, a book move and its weight,
* and a comment describing the position after the book move.
*
* @author Johan Dykstrom
*/
public class OpeningBookParser {

private static final Logger TLOG = Logger.getLogger(OpeningBookParser.class.getName());

/** Positions and corresponding moves. */
private static Map<Position, List<BookMove>> positions;

// ------------------------------------------------------------------------

/**
* Loads the opening book file.
*
* @param file The opening book file.
* @return The opening book.
* @throws ParseException If the opening book file cannot be loaded.
* @throws IOException If the opening book file cannot be read.
* @throws ParseException If the opening book file cannot be parsed.
*/
public static OpeningBook parse(File file) throws IOException, ParseException {
positions = new HashMap<>();
Map<Position, List<BookMove>> positions;

long start = System.currentTimeMillis();
try {
JAXBContext context = JAXBContext.newInstance(XmlBookMove.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
XmlBookMove topMove = (XmlBookMove) unmarshaller.unmarshal(file);
for (XmlBookMove move : topMove.getSubMoves()) {
parseMove(new LinkedList<>(), move);
}
} catch (JAXBException e) {
TLOG.severe("Failed to load file '" + file.getName() + "': " + e);
if (e.getLinkedException() instanceof IOException) {
throw (IOException) e.getLinkedException();
} else {
throw new ParseException("Failed to load file '" + file.getName() + "'", 0);
}
} catch (NumberFormatException e) {
TLOG.severe("Failed to load file '" + file.getName() + "': " + e);
throw new ParseException("Failed to load file '" + file.getName() + "'", 0);
// Read all lines and remove empty lines and comments
List<String> lines = Files.lines(file.toPath())
.map(String::trim)
.filter(line -> !line.isEmpty() && !line.startsWith("#"))
.collect(toList());
positions = parseLines(lines);
} catch (IOException e) {
TLOG.severe("Failed to open file '" + file.getName() + "': " + e);
throw e;
}
long stop = System.currentTimeMillis();
TLOG.info("Loaded opening book in " + (stop - start) + " ms");
Expand All @@ -106,51 +78,51 @@ public static OpeningBook parse(File file) throws IOException, ParseException {
}

/**
* Parses a move, adds it to the opening book as a possible move in the
* current position, and parses all sub moves recursively. If the given
* move is invalid, this move and all of its sub moves are ignored, but
* the rest of the opening book is still read.
* Parses all non-empty lines that were read from the opening book file.
*
* @param moves The list of moves made so far in this opening line.
* @param xmlMove An XML move read from the opening book file.
* @param lines The opening lines to parse.
* @return A map of positions and book moves.
*/
private static void parseMove(LinkedList<String> moves, XmlBookMove xmlMove) {
// Get attribute values
String move = xmlMove.getCan();
int weight = xmlMove.getWeight();

// Add this move to the opening book
try {
add(moves, move, weight);
} catch (IllegalMoveException ime) {
TLOG.warning("Illegal move [" + move + ", " + weight + "] in opening line " + moves + ": " + ime);
return;
}
static Map<Position, List<BookMove>> parseLines(List<String> lines) throws ParseException {
Map<Position, List<BookMove>> positions = new HashMap<>();

// If we could add this move OK, continue to parse each sub move recursively
moves.addLast(move);
for (XmlBookMove subMove : xmlMove.getSubMoves()) {
parseMove(moves, subMove);
}
moves.removeLast();
}
for (String line : lines) {
String[] fields = line.split(";", -1);
if (fields.length != 3) {
throw new ParseException("Syntax error on line '" + line + "'", 0);
}

/**
* Adds the supplied move as a possible move in the current position.
*
* @param moves The list of moves made so far in this opening line.
* @param move The move to add, in coordinate algebraic notation.
* @param weight The weight of the move in this position.
* @throws IllegalMoveException If any of the moves in the move list, or the new move, is illegal.
*/
private static void add(List<String> moves, String move, int weight) throws IllegalMoveException {
// Set up a new position
Position position = Position.of(moves);
String[] moves = fields[0].trim().split(" ");
String bookMove = fields[1].trim();
// Ignore the comment field

// Create book position from available moves
Position position;
try {
if (moves.length == 1 && moves[0].isBlank()) {
position = Position.START;
} else {
position = Position.of(asList(moves));
}
} catch (IllegalMoveException e) {
TLOG.warning("Illegal move in opening line " + Arrays.toString(moves) + ": " + e);
continue;
}

// Get the list of possible moves for this position
List<BookMove> list = positions.computeIfAbsent(position, key -> new ArrayList<>());
// Get/create the list of possible moves for this position
List<BookMove> list = positions.computeIfAbsent(position, key -> new ArrayList<>());

// Create book move and add to list
try {
String[] moveAndWeight = bookMove.split(("/"));
list.add(new BookMove(MoveParser.parse(moveAndWeight[0], position), Integer.parseInt(moveAndWeight[1])));
} catch (IllegalMoveException e) {
TLOG.warning("Illegal move in opening line " + Arrays.toString(moves) + ": " + bookMove);
} catch (NumberFormatException e) {
TLOG.warning("Illegal weight in opening line " + Arrays.toString(moves) + ": " + bookMove);
}
}

// Create the new move and add it to the list
list.add(new BookMove(MoveParser.parse(move, position), weight));
return positions;
}
}
1 change: 0 additions & 1 deletion src/main/java/se/dykstrom/ronja/common/model/Square.java
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ public class Square {
public static final long E8 = 1L << 60L;
public static final long F8 = 1L << 61L;
public static final long G8 = 1L << 62L;
@SuppressWarnings("NumericOverflow")
public static final long H8 = 1L << 63L;

private static final String SQUARES =
Expand Down
14 changes: 7 additions & 7 deletions src/main/java/se/dykstrom/ronja/common/parser/PgnParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@

package se.dykstrom.ronja.common.parser;

import static se.dykstrom.ronja.common.utils.ArrayUtils.toArray;
import se.dykstrom.ronja.common.model.Color;
import se.dykstrom.ronja.common.model.Game;
import se.dykstrom.ronja.common.model.Position;
import se.dykstrom.ronja.engine.utils.AppConfig;

import java.net.InetAddress;
import java.net.UnknownHostException;
Expand All @@ -26,10 +29,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import se.dykstrom.ronja.common.model.Color;
import se.dykstrom.ronja.common.model.Game;
import se.dykstrom.ronja.common.model.Position;
import se.dykstrom.ronja.engine.utils.AppConfig;
import static se.dykstrom.ronja.common.utils.ArrayUtils.toArray;

/**
* A class that can parse and format files specified in Portable Game Notation (PGN).
Expand All @@ -38,8 +38,8 @@
*/
public final class PgnParser {

private static final DateTimeFormatter DF = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private static final DateTimeFormatter TF = DateTimeFormatter.ofPattern("HH:mm:ss");
private static final DateTimeFormatter DF = DateTimeFormatter.ISO_LOCAL_DATE;
private static final DateTimeFormatter TF = DateTimeFormatter.ofPattern("HH:mm");

private static final String BACKSLASH_REPLACEMENT = Matcher.quoteReplacement("\\\\");
private static final String QUOTE_REPLACEMENT = Matcher.quoteReplacement("\\\"");
Expand Down
Loading

0 comments on commit a316d83

Please sign in to comment.