--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+ ~ Copyright (c) 2018. Developed by Hedgecode.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.hedgecode.maven</groupId>
+ <artifactId>lib-parent</artifactId>
+ <version>2</version>
+ <relativePath>../lib-parent/pom.xml</relativePath>
+ </parent>
+
+ <groupId>org.hedgecode.chess</groupId>
+ <artifactId>chesshog</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <packaging>jar</packaging>
+
+ <name>Hedgecode Chess</name>
+ <description>
+ Hedgecode Chess.
+ </description>
+ <inceptionYear>2018</inceptionYear>
+
+ <url>http://lib.hedgecode.org/${project.artifactId}/</url>
+
+ <scm>
+ <connection>scm:svn:http://svn.hedgecode.org/lib/${project.artifactId}/trunk/</connection>
+ <developerConnection>scm:svn:https://svn.hedgecode.org/lib/${project.artifactId}/trunk/</developerConnection>
+ <url>http://svn.hedgecode.org/lib/${project.artifactId}/trunk/</url>
+ </scm>
+
+ <issueManagement>
+ <system>JIRA</system>
+ <url>http://issues.hedgecode.org/browse/${issueKey}/component/${issueComponentId}</url>
+ </issueManagement>
+
+ <distributionManagement>
+ <site>
+ <id>hedgecode.website</id>
+ <name>Hedgecode Libs Website</name>
+ <url>dav:https://hedgecode.org/libs/${project.artifactId}/</url>
+ </site>
+ </distributionManagement>
+
+ <properties>
+ <junitVersion>4.12</junitVersion>
+ <commonsConfigVersion>1.10</commonsConfigVersion>
+ <commonsCollectionVersion>3.2.1</commonsCollectionVersion>
+ <mavenDependencyPluginVersion>2.8</mavenDependencyPluginVersion>
+ <mavenAssemblyPluginVersion>2.4.1</mavenAssemblyPluginVersion>
+ <issueComponentId>10030</issueComponentId>
+ <issueNumber>9</issueNumber>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>${junitVersion}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-configuration</groupId>
+ <artifactId>commons-configuration</artifactId>
+ <version>${commonsConfigVersion}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ <version>${commonsCollectionVersion}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>${mavenDependencyPluginVersion}</version>
+ <executions>
+ <execution>
+ <id>copy-dependencies</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>copy-dependencies</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${project.build.directory}/lib</outputDirectory>
+ <overWriteReleases>false</overWriteReleases>
+ <overWriteSnapshots>false</overWriteSnapshots>
+ <overWriteIfNewer>true</overWriteIfNewer>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>${mavenJarPluginVersion}</version>
+ <configuration>
+ <archive>
+ <manifest>
+ <addClasspath>true</addClasspath>
+ <classpathPrefix>lib/</classpathPrefix>
+ <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
+ <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+ <mainClass>org.hedgecode.chess.ChessHogApp</mainClass>
+ </manifest>
+ <manifestEntries>
+ <Implementation-Title>${project.artifactId}</Implementation-Title>
+ </manifestEntries>
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-release-plugin</artifactId>
+ <version>${mavenReleasePluginVersion}</version>
+ <configuration>
+ <tagBase>https://svn.hedgecode.org/lib/${project.artifactId}/tags</tagBase>
+ <branchBase>https://svn.hedgecode.org/lib/${project.artifactId}/branches</branchBase>
+ <preparationGoals>clean install</preparationGoals>
+ <goals>deploy</goals>
+ <releaseProfiles>release</releaseProfiles>
+ <scmCommentPrefix xml:space="preserve">[${issueKey}-${issueNumber}] </scmCommentPrefix>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-project-info-reports-plugin</artifactId>
+ <version>${mavenReportsPluginVersion}</version>
+ <configuration>
+ <dependencyLocationsEnabled>false</dependencyLocationsEnabled>
+ </configuration>
+ <reportSets>
+ <reportSet>
+ <reports>
+ <report>index</report>
+ <report>summary</report>
+ <report>dependency-info</report>
+ <report>project-team</report>
+ <report>scm</report>
+ <report>dependency-management</report>
+ <report>dependencies</report>
+ <report>plugin-management</report>
+ <report>plugins</report>
+ <report>distribution-management</report>
+ </reports>
+ </reportSet>
+ </reportSets>
+ </plugin>
+ </plugins>
+ </reporting>
+
+ <profiles>
+ <profile>
+ <id>jar-with-dependencies</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>${mavenAssemblyPluginVersion}</version>
+ <configuration>
+ <archive>
+ <manifest>
+ <addClasspath>true</addClasspath>
+ <classpathPrefix>lib/</classpathPrefix>
+ <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
+ <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+ <mainClass>org.hedgecode.chess.ChessHogApp</mainClass>
+ </manifest>
+ <manifestEntries>
+ <Implementation-Title>${project.artifactId}</Implementation-Title>
+ </manifestEntries>
+ </archive>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>reporting</id>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <sourceFileExcludes>
+ <!--<exclude>org/hedgecode/chess/*.java</exclude>-->
+ </sourceFileExcludes>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+ </profile>
+ </profiles>
+
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess;
+
+import org.hedgecode.chess.ascii.ASCIIBuilder;
+import org.hedgecode.chess.fen.FENBuilder;
+import org.hedgecode.chess.position.Builder;
+import org.hedgecode.chess.tcd.TCDBuilder;
+import org.hedgecode.chess.wiki.WikiBuilder;
+
+/**
+ * Chess Position & Game Builders.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum Builders {
+
+ FEN ( FENBuilder.getInstance() ),
+ TCD ( TCDBuilder.getInstance() ),
+ ASCII ( ASCIIBuilder.getInstance() ),
+ WIKI ( WikiBuilder.getInstance() );
+
+ private Builder builder;
+
+ Builders(Builder builder) {
+ this.builder = builder;
+ }
+
+ public Builder builder() {
+ return builder;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess;
+
+/**
+ * ChessHog Main Application.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class ChessHogApp {
+
+ public static void main(String[] args) {
+
+
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ResourceBundle;
+
+/**
+ * Store of library constants.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class ChessHogConstants {
+
+ public static final Charset CHARSET = StandardCharsets.UTF_8;
+
+ public static final String LOCALE_BUNDLE_FILE = "org.hedgecode.chess.LocalStrings";
+
+
+ private ChessHogConstants() {
+ throw new AssertionError(
+ "No org.hedgecode.chess.ChessHogConstants instances!"
+ );
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess;
+
+import org.hedgecode.chess.ascii.ASCIIParser;
+import org.hedgecode.chess.fen.FENParser;
+import org.hedgecode.chess.position.Parser;
+import org.hedgecode.chess.tcd.TCDParser;
+import org.hedgecode.chess.wiki.WikiParser;
+
+/**
+ * Chess Position & Game Parsers.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum Parsers {
+
+ FEN ( FENParser.getInstance() ),
+ TCD ( TCDParser.getInstance() ),
+ ASCII ( ASCIIParser.getInstance() ),
+ WIKI ( WikiParser.getInstance() );
+
+ private Parser parser;
+
+ Parsers(Parser parser) {
+ this.parser = parser;
+ }
+
+ public Parser parser() {
+ return parser;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.ascii;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.hedgecode.chess.position.Color;
+import org.hedgecode.chess.position.ColorPiece;
+import org.hedgecode.chess.position.Piece;
+
+/**
+ * ASCII chess diagram constants.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class ASCII {
+
+ public static final String CRLF = System.lineSeparator();
+
+ public static final char EMPTY = ' ';
+ public static final String INDENT = " ";
+
+ public static final char WHITE_PAWN = 'P';
+ public static final char WHITE_KNIGHT = 'N';
+ public static final char WHITE_BISHOP = 'B';
+ public static final char WHITE_ROOK = 'R';
+ public static final char WHITE_QUEEN = 'Q';
+ public static final char WHITE_KING = 'K';
+
+ public static final char BLACK_PAWN = 'p';
+ public static final char BLACK_KNIGHT = 'n';
+ public static final char BLACK_BISHOP = 'b';
+ public static final char BLACK_ROOK = 'r';
+ public static final char BLACK_QUEEN = 'q';
+ public static final char BLACK_KING = 'k';
+
+ public static final char[] NOTATION = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' };
+
+ public static final String HYPHEN_LINE = "+-------------------------------+";
+ public static final String HYPHEN_SEP = "|";
+
+ public static final String DOT_LINE = "+------------------------+";
+ public static final String DOT_EDGE = "|";
+ public static final char DOT_EMPTY = '.';
+
+ public static final String TIGHT_LINE = " ___ ___ ___ ___ ___ ___ ___ ___ ";
+ public static final String TIGHT_SEP = "|";
+ public static final char TIGHT_EMPTY = '_';
+
+ public static final String CP866_HEADER = "╔═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╗";
+ public static final String CP866_LINE = "╟───┼───┼───┼───┼───┼───┼───┼───╢";
+ public static final String CP866_FOOTER = "╚═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╝";
+ public static final String CP866_SEP = "│";
+ public static final String CP866_EDGE = "║";
+
+ public static final String BAR_REGEX = HYPHEN_SEP + TIGHT_SEP + CP866_SEP;
+ public static final String EDGE_REGEX = HYPHEN_SEP + DOT_EDGE + TIGHT_SEP + CP866_EDGE;
+
+ public static final String PIECE_REGEX = "PNBRQKpnbrqk";
+ public static final String DOT_PIECE_REGEX = PIECE_REGEX + DOT_EMPTY;
+
+ private static final Pattern PIECE_PATTERN = Pattern.compile(
+ String.format("([%s])", PIECE_REGEX)
+ );
+
+ private static final Map<ColorPiece, Character> PIECES = new HashMap<ColorPiece, Character>() {
+ {
+ put(ColorPiece.WHITE_PAWN, WHITE_PAWN); put(ColorPiece.BLACK_PAWN, BLACK_PAWN);
+ put(ColorPiece.WHITE_KNIGHT, WHITE_KNIGHT); put(ColorPiece.BLACK_KNIGHT, BLACK_KNIGHT);
+ put(ColorPiece.WHITE_BISHOP, WHITE_BISHOP); put(ColorPiece.BLACK_BISHOP, BLACK_BISHOP);
+ put(ColorPiece.WHITE_ROOK, WHITE_ROOK); put(ColorPiece.BLACK_ROOK, BLACK_ROOK);
+ put(ColorPiece.WHITE_QUEEN, WHITE_QUEEN); put(ColorPiece.BLACK_QUEEN, BLACK_QUEEN);
+ put(ColorPiece.WHITE_KING, WHITE_KING); put(ColorPiece.BLACK_KING, BLACK_KING);
+ }
+ };
+
+ private static ASCIIBoardType boardType = ASCIIBoardType.HYPHEN;
+ private static boolean withNotation = false;
+
+ private ASCII() {
+ }
+
+ public static void setType(ASCIIBoardType type) {
+ boardType = type;
+ }
+
+ public static ASCIIBoardType getType() {
+ return boardType;
+ }
+
+ public static void setNotation(boolean isNotation) {
+ withNotation = isNotation;
+ }
+
+ public static boolean isNotation() {
+ return withNotation;
+ }
+
+ public static ColorPiece getColorPiece(String piece) {
+ if (piece != null) {
+ Matcher matcher = PIECE_PATTERN.matcher(piece);
+ if (matcher.find()) {
+ char chPiece = matcher.group(1).charAt(0);
+ for (Map.Entry<ColorPiece, Character> entry : PIECES.entrySet()) {
+ if (entry.getValue() == chPiece)
+ return entry.getKey();
+ }
+ }
+ }
+ return null;
+ }
+
+ public static char getAsciiPiece(Color color, Piece piece) {
+ return getAsciiPiece(
+ ColorPiece.getColorPiece(color, piece)
+ );
+ }
+
+ public static char getAsciiPiece(ColorPiece colorPiece) {
+ return (colorPiece != null)
+ ? PIECES.get(colorPiece)
+ : EMPTY;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.ascii;
+
+/**
+ * ASCII chess diagram board types.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum ASCIIBoardType {
+
+ HYPHEN (
+ ASCII.HYPHEN_LINE, ASCII.HYPHEN_LINE, ASCII.HYPHEN_LINE,
+ ASCII.HYPHEN_SEP, ASCII.HYPHEN_SEP, ASCII.EMPTY, ASCII.EMPTY
+ ),
+
+ DOT (
+ ASCII.DOT_LINE, null, ASCII.DOT_LINE,
+ null, ASCII.DOT_EDGE, ASCII.DOT_EMPTY, ASCII.EMPTY
+ ),
+
+ TIGHT (
+ ASCII.TIGHT_LINE, null, null,
+ ASCII.TIGHT_SEP, ASCII.TIGHT_SEP, ASCII.TIGHT_EMPTY, ASCII.TIGHT_EMPTY
+ ),
+
+ CP866 (
+ ASCII.CP866_HEADER, ASCII.CP866_LINE, ASCII.CP866_FOOTER,
+ ASCII.CP866_SEP, ASCII.CP866_EDGE, ASCII.EMPTY, ASCII.EMPTY
+ );
+
+ private String header;
+ private String line;
+ private String footer;
+ private String separator;
+ private String edge;
+ private char empty;
+ private char space;
+
+ ASCIIBoardType(
+ String header, String line, String footer,
+ String separator, String edge,
+ char empty, char space
+ ) {
+ this.header = header;
+ this.line = line;
+ this.footer = footer;
+ this.separator = separator;
+ this.edge = edge;
+ this.empty = empty;
+ this.space = space;
+ }
+
+ public String getHeader() {
+ return header;
+ }
+
+ public String getLine() {
+ return line;
+ }
+
+ public String getFooter() {
+ return footer;
+ }
+
+ public String getSeparator() {
+ return separator;
+ }
+
+ public String getEdge() {
+ return edge;
+ }
+
+ public char getEmpty() {
+ return empty;
+ }
+
+ public char getSpace() {
+ return space;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.ascii;
+
+import java.util.Map;
+
+import org.hedgecode.chess.Parsers;
+import org.hedgecode.chess.position.Builder;
+import org.hedgecode.chess.position.ColorPiece;
+import org.hedgecode.chess.position.ParseException;
+import org.hedgecode.chess.position.Position;
+import org.hedgecode.chess.position.Square;
+
+/**
+ * ASCII chess diagram builder.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class ASCIIBuilder implements Builder {
+
+ private static Builder _instance = new ASCIIBuilder();
+
+ private ASCIIBuilder() {
+ }
+
+ @Override
+ public String build(Position position) {
+ return _build(
+ ASCII.getType(), position
+ );
+ }
+
+ private String _build(ASCIIBoardType type, Position position) {
+ StringBuilder sb = new StringBuilder();
+ Map<Square, ColorPiece> squares = position.getSquares();
+
+ String indent = ASCII.INDENT;
+ char empty = type.getEmpty();
+ char space = type.getSpace();
+ String separator = type.getSeparator();
+
+ if (ASCII.isNotation())
+ sb.append(indent).append(
+ _buildNotation(separator != null)
+ ).append(ASCII.CRLF);
+
+ if (type.getHeader() != null)
+ sb.append(indent).append(type.getHeader()).append(ASCII.CRLF);
+
+ for (int i = Square.getSize() - 1; i >= 0; --i) {
+ if (ASCII.isNotation())
+ sb.append(i + 1).append(ASCII.EMPTY);
+ else
+ sb.append(indent);
+
+ sb.append(type.getEdge());
+
+ for (int j = 0; j < Square.getSize(); ++j) {
+ Square square = Square.getSquare(j, i);
+ ColorPiece piece = squares.get(square);
+ char pieceChar = (piece != null) ? ASCII.getAsciiPiece(piece) : empty;
+ sb.append(space).append(pieceChar).append(space);
+ if (separator != null && j < Square.getSize() - 1)
+ sb.append(separator);
+ }
+
+ sb.append(type.getEdge());
+ if (ASCII.isNotation())
+ sb.append(ASCII.EMPTY).append(i + 1);
+ else
+ sb.append(indent);
+
+ sb.append(ASCII.CRLF);
+
+ if (i > 0 && type.getLine() != null)
+ sb.append(indent).append(type.getLine()).append(ASCII.CRLF);
+ }
+
+ if (type.getFooter() != null)
+ sb.append(indent).append(type.getFooter()).append(ASCII.CRLF);
+
+ if (ASCII.isNotation())
+ sb.append(indent).append(
+ _buildNotation(separator != null)
+ ).append(ASCII.CRLF);
+
+ return sb.toString();
+ }
+
+ private String _buildNotation(boolean withSeparator) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(ASCII.EMPTY);
+ for (char letter : ASCII.NOTATION) {
+ sb.append(ASCII.EMPTY).append(letter).append(ASCII.EMPTY);
+ if (withSeparator)
+ sb.append(ASCII.EMPTY);
+ }
+ sb.append(ASCII.EMPTY);
+ return sb.toString();
+ }
+
+ public static Builder getInstance() {
+ return _instance;
+ }
+
+
+ public static void main(String[] args) throws ParseException {
+ ASCII.setType(ASCIIBoardType.HYPHEN);
+ ASCII.setNotation(false);
+
+ Position position = Parsers.FEN.parser().parse(
+ "r7/7p/8/8/8/8/PPPPPP2/1N1Q2NR w KQkq - 20 20"
+ );
+ System.out.println(
+ getInstance().build(position)
+ );
+
+/*
+ Position position = Parsers.WIKI.parser().parse(
+ "{{Шахматная диаграмма\n" +
+ "|\n" +
+ "|\n" +
+ "|rd|nd|bd|qd|kd|bd|nd|rd\n" +
+ "|pd|pd| |pd|pd|pd|pd|pd\n" +
+ "| | | | | | | |\n" +
+ "| | | | | | | |\n" +
+ "| | | |pd|pl| | |\r\n" +
+ "| | |pl| | | | |\n" +
+ "|pl|pl| | | |pl|pl|pl\n" +
+ "|rl|nl|bl|ql|kl|bl|nl|rl\n" +
+ "| }}"
+ );
+ System.out.println(
+ getInstance().build(position)
+ );
+*/
+
+/*
+ Position position = Parsers.TCD.parser().parse("AHL30v0GIv+PqX16ap-G");
+ System.out.println(
+ getInstance().build(position)
+ );
+*/
+
+ /*
+ System.out.println(
+ getInstance().build(Positions.INITIAL.getPosition())
+ );
+*/
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.ascii;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.hedgecode.chess.Builders;
+import org.hedgecode.chess.position.Color;
+import org.hedgecode.chess.position.ParseException;
+import org.hedgecode.chess.position.Parser;
+import org.hedgecode.chess.position.Position;
+import org.hedgecode.chess.position.Positions;
+import org.hedgecode.chess.position.Square;
+
+/**
+ * ASCII chess diagram parser.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class ASCIIParser implements Parser {
+
+ private static final String LINE_REGEX = "\\r?\\n";
+ private static final String BAR_SQUARE_REGEX = String.format("[%s]", ASCII.BAR_REGEX);
+ private static final String DOT_SQUARE_REGEX = String.format("[^%s]+", ASCII.DOT_PIECE_REGEX);
+
+ private static final Pattern BAR_PATTERN =
+ Pattern.compile(
+ String.format(
+ "^.*[%s](([^%s]+[%s]){%d}[^%s]+)[%s].*$",
+ ASCII.EDGE_REGEX, ASCII.BAR_REGEX, ASCII.BAR_REGEX,
+ Square.getSize() - 1, ASCII.EDGE_REGEX, ASCII.EDGE_REGEX
+ )
+ );
+
+ private static final Pattern DOT_PATTERN =
+ Pattern.compile(
+ String.format(
+ "^.*[%s](([^%s]+[%s]){%d}[^%s]+)[%s].*$",
+ ASCII.DOT_EDGE, ASCII.DOT_PIECE_REGEX, ASCII.DOT_PIECE_REGEX,
+ Square.getSize(), ASCII.DOT_PIECE_REGEX, ASCII.DOT_EDGE
+ )
+ );
+
+ private static Parser _instance = new ASCIIParser();
+
+ private ASCIIParser() {
+ }
+
+ @Override
+ public Position parse(String string) throws ParseException {
+ return _parse(
+ string.split(LINE_REGEX)
+ );
+ }
+
+ private Position _parse(String[] strings) throws ParseException {
+ String[] lines;
+ String squareRegex = BAR_SQUARE_REGEX;
+ lines = _parseLines(strings, BAR_PATTERN);
+ if (lines.length != Square.getSize()) {
+ squareRegex = DOT_SQUARE_REGEX;
+ lines = _parseLines(strings, DOT_PATTERN);
+ if (lines.length != Square.getSize())
+ throw new ParseException("parse.ascii.incorrect.board");
+ }
+ Position position = Positions.EMPTY.getPosition();
+ _parsePieces(
+ lines,
+ position,
+ squareRegex
+ );
+ return position;
+ }
+
+ private String[] _parseLines(String[] strings, Pattern linePattern) {
+ List<String> lines = new ArrayList<>();
+ for (String line : strings) {
+ Matcher matcher = linePattern.matcher(line);
+ if (matcher.find()) {
+ lines.add(
+ matcher.group(1).trim()
+ );
+ }
+ }
+ return lines.toArray(
+ new String[lines.size()]
+ );
+ }
+
+ private void _parsePieces(String[] lines, Position position, String squareRegex) throws ParseException {
+ for (int i = 0; i < lines.length; ++i) {
+ int line = lines.length - i;
+ String[] pieces = lines[i].split(squareRegex, -1);
+ if (pieces.length != Square.getSize())
+ throw new ParseException("parse.ascii.incorrect.board");
+ for (int j = 0; j < pieces.length; ++j) {
+ position.setPiece(
+ ASCII.getColorPiece(pieces[j]),
+ Square.getSquare(j, line - 1)
+ );
+ }
+ }
+ }
+
+ public static Parser getInstance() {
+ return _instance;
+ }
+
+
+ public static void main(String[] args) throws ParseException {
+ ASCII.setType(ASCIIBoardType.DOT);
+ ASCII.setNotation(false);
+
+ // Position position = Positions.INITIAL.getPosition();
+ Position position = Positions.EMPTY.getPosition();
+ position.setKing(Color.WHITE, Square.A1);
+ position.setPawn(Color.WHITE, Square.A2);
+ position.setPawn(Color.WHITE, Square.E4);
+ position.setQueen(Color.WHITE, Square.A7);
+ position.setKing(Color.BLACK, Square.H8);
+ position.setPawn(Color.BLACK, Square.G7);
+ position.setPawn(Color.BLACK, Square.H7);
+ position.setKnight(Color.BLACK, Square.G2);
+ position.setBishop(Color.BLACK, Square.D4);
+ position.setRook(Color.BLACK, Square.E2);
+
+ String ascii = Builders.ASCII.builder().build(position);
+ System.out.println(
+ ascii
+ );
+
+ position = getInstance().parse(ascii);
+
+ ASCII.setType(ASCIIBoardType.HYPHEN);
+ ascii = Builders.ASCII.builder().build(position);
+ System.out.println(
+ ascii
+ );
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.fen;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hedgecode.chess.position.Castle;
+import org.hedgecode.chess.position.Color;
+import org.hedgecode.chess.position.ColorPiece;
+import org.hedgecode.chess.position.Piece;
+import org.hedgecode.chess.position.Square;
+
+/**
+ * Forsyth–Edwards Notation (FEN) constants.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class FEN {
+
+ enum Fields {
+ PIECES (0, "[pPnNbBrRqQkK1-8]+/?"),
+ MOVE (1, "[wb]"),
+ CASTLE (2, "[qQkK]+|-"),
+ EN_PASSANT (3, "[a-h][36]|-"),
+ HALFMOVE (4, "[0-9]+"),
+ FULLMOVE (5, "[1-9][0-9]*");
+
+ private int index;
+ private String regex;
+
+ Fields(int index, String regex) {
+ this.index = index;
+ this.regex = regex;
+ }
+
+ public int index() {
+ return index;
+ }
+
+ public String regex() {
+ return regex;
+ }
+ }
+
+ public static final char WHITE = 'w';
+ public static final char BLACK = 'b';
+ public static final char HYPHEN = '-';
+
+ public static final String FIELDS_SEP = " ";
+ public static final String LINE_SEP = "/";
+
+ public static final char WHITE_PAWN = 'P';
+ public static final char WHITE_KNIGHT = 'N';
+ public static final char WHITE_BISHOP = 'B';
+ public static final char WHITE_ROOK = 'R';
+ public static final char WHITE_QUEEN = 'Q';
+ public static final char WHITE_KING = 'K';
+
+ public static final char BLACK_PAWN = 'p';
+ public static final char BLACK_KNIGHT = 'n';
+ public static final char BLACK_BISHOP = 'b';
+ public static final char BLACK_ROOK = 'r';
+ public static final char BLACK_QUEEN = 'q';
+ public static final char BLACK_KING = 'k';
+
+ private static final Map<Color, Character> COLORS = new HashMap<Color, Character>() {
+ {
+ put(Color.WHITE, WHITE);
+ put(Color.BLACK, BLACK);
+ }
+ };
+
+ private static final Map<ColorPiece, Character> PIECES = new HashMap<ColorPiece, Character>() {
+ {
+ put(ColorPiece.WHITE_PAWN, WHITE_PAWN); put(ColorPiece.BLACK_PAWN, BLACK_PAWN);
+ put(ColorPiece.WHITE_KNIGHT, WHITE_KNIGHT); put(ColorPiece.BLACK_KNIGHT, BLACK_KNIGHT);
+ put(ColorPiece.WHITE_BISHOP, WHITE_BISHOP); put(ColorPiece.BLACK_BISHOP, BLACK_BISHOP);
+ put(ColorPiece.WHITE_ROOK, WHITE_ROOK); put(ColorPiece.BLACK_ROOK, BLACK_ROOK);
+ put(ColorPiece.WHITE_QUEEN, WHITE_QUEEN); put(ColorPiece.BLACK_QUEEN, BLACK_QUEEN);
+ put(ColorPiece.WHITE_KING, WHITE_KING); put(ColorPiece.BLACK_KING, BLACK_KING);
+ }
+ };
+
+ private FEN() {
+ }
+
+ public static Color getColor(char color) {
+ for (Map.Entry<Color, Character> entry : COLORS.entrySet()) {
+ if (entry.getValue() == color)
+ return entry.getKey();
+ }
+ return null;
+ }
+
+ public static String getColor(Color color) {
+ return String.valueOf(
+ color != null
+ ? COLORS.get(color)
+ : COLORS.get(Color.WHITE)
+ );
+ }
+
+ public static ColorPiece getColorPiece(char piece) {
+ for (Map.Entry<ColorPiece, Character> entry : PIECES.entrySet()) {
+ if (entry.getValue() == piece)
+ return entry.getKey();
+ }
+ return null;
+ }
+
+ public static char getFenPiece(Color color, Piece piece) {
+ return getFenPiece(
+ ColorPiece.getColorPiece(color, piece)
+ );
+ }
+
+ public static char getFenPiece(ColorPiece colorPiece) {
+ return PIECES.get(colorPiece);
+ }
+
+ public static Castle getCastle(Color color, String castles) {
+ Castle castle;
+ if (castles.indexOf(HYPHEN) >= 0) {
+ castle = Castle.NONE;
+ } else {
+ boolean isKing = false, isQueen = false;
+ switch (color) {
+ case WHITE:
+ isKing = (castles.indexOf(WHITE_KING) >= 0);
+ isQueen = (castles.indexOf(WHITE_QUEEN) >= 0);
+ break;
+ case BLACK:
+ isKing = (castles.indexOf(BLACK_KING) >= 0);
+ isQueen = (castles.indexOf(BLACK_QUEEN) >= 0);
+ break;
+ }
+ castle = isKing && isQueen ? Castle.BOTH
+ : isKing ? Castle.KING
+ : isQueen ? Castle.QUEEN
+ : Castle.NONE;
+ }
+ return castle;
+ }
+
+ public static String getCastle(Castle whiteCastle, Castle blackCastle) {
+ StringBuilder sb = new StringBuilder();
+ switch (whiteCastle) {
+ case KING:
+ sb.append(WHITE_KING);
+ break;
+ case QUEEN:
+ sb.append(WHITE_QUEEN);
+ break;
+ case BOTH:
+ sb.append(WHITE_KING).append(WHITE_QUEEN);
+ break;
+ }
+ switch (blackCastle) {
+ case KING:
+ sb.append(BLACK_KING);
+ break;
+ case QUEEN:
+ sb.append(BLACK_QUEEN);
+ break;
+ case BOTH:
+ sb.append(BLACK_KING).append(BLACK_QUEEN);
+ break;
+ }
+ String castles = sb.toString();
+ return castles.isEmpty()
+ ? String.valueOf(HYPHEN)
+ : castles;
+ }
+
+ public static Square getEnPassant(String enPassant) {
+ if (enPassant.indexOf(HYPHEN) < 0) {
+ return Square.getSquare(enPassant);
+ }
+ return null;
+ }
+
+ public static String getEnPassant(Square square){
+ return (square != null)
+ ? square.name().toLowerCase()
+ : String.valueOf(HYPHEN);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.fen;
+
+import java.util.Map;
+
+import org.hedgecode.chess.Parsers;
+import org.hedgecode.chess.position.Builder;
+import org.hedgecode.chess.position.Color;
+import org.hedgecode.chess.position.ColorPiece;
+import org.hedgecode.chess.position.ParseException;
+import org.hedgecode.chess.position.Position;
+import org.hedgecode.chess.position.Square;
+
+/**
+ * Forsyth–Edwards Notation (FEN) builder.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class FENBuilder implements Builder {
+
+ private static Builder _instance = new FENBuilder();
+
+ private FENBuilder() {
+ }
+
+ @Override
+ public String build(Position position) {
+ return _build(
+ position
+ );
+ }
+
+ private String _build(Position position) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(
+ _buildPosition(position)
+ ).append(
+ FEN.FIELDS_SEP
+ ).append(
+ FEN.getColor(
+ position.getMove()
+ )
+ ).append(
+ FEN.FIELDS_SEP
+ ).append(
+ FEN.getCastle(
+ position.getCastle(Color.WHITE),
+ position.getCastle(Color.BLACK)
+ )
+ ).append(
+ FEN.FIELDS_SEP
+ ).append(
+ FEN.getEnPassant(
+ position.getEnPassant()
+ )
+ ).append(
+ FEN.FIELDS_SEP
+ ).append(
+ position.getHalfMove()
+ ).append(
+ FEN.FIELDS_SEP
+ ).append(
+ position.getFullMove()
+ );
+ return sb.toString();
+ }
+
+ private String _buildPosition(Position position) {
+ StringBuilder sb = new StringBuilder();
+ Map<Square, ColorPiece> squares = position.getSquares();
+ for (int i = Square.getSize() - 1; i >= 0; --i) {
+ int empty = 0;
+ for (int j = 0; j < Square.getSize(); ++j) {
+ Square square = Square.getSquare(j, i);
+ ColorPiece piece = squares.get(square);
+ if (piece != null) {
+ if (empty > 0)
+ sb.append(empty);
+ sb.append(
+ FEN.getFenPiece(piece)
+ );
+ empty = 0;
+ } else {
+ ++empty;
+ }
+ }
+ if (empty > 0)
+ sb.append(empty);
+ if (i > 0)
+ sb.append(FEN.LINE_SEP);
+ }
+ return sb.toString();
+ }
+
+ public static Builder getInstance() {
+ return _instance;
+ }
+
+
+ public static void main(String[] args) throws ParseException {
+
+ Position position = Parsers.FEN.parser().parse(
+ "r7/7p/8/8/8/8/PPPPPP2/1N1Q2NR w KQkq a3 1 20"
+ );
+ System.out.println(
+ getInstance().build(position)
+ );
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.fen;
+
+import java.util.regex.Pattern;
+
+import org.hedgecode.chess.position.Color;
+import org.hedgecode.chess.position.ParseException;
+import org.hedgecode.chess.position.Parser;
+import org.hedgecode.chess.position.Position;
+import org.hedgecode.chess.position.Positions;
+import org.hedgecode.chess.position.Square;
+
+/**
+ * Forsyth–Edwards Notation (FEN) parser.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class FENParser implements Parser {
+
+ private static final String SPLIT_REGEX = "\\s+";
+ private static final String LINE_REGEX = FEN.LINE_SEP;
+
+ private static final Pattern PATTERN =
+ Pattern.compile(
+ String.format("^(%s){%d} (%s) (%s) (%s) (%s) (%s)$",
+ FEN.Fields.PIECES.regex(), Square.getSize(),
+ FEN.Fields.MOVE.regex(),
+ FEN.Fields.CASTLE.regex(), FEN.Fields.EN_PASSANT.regex(),
+ FEN.Fields.HALFMOVE.regex(), FEN.Fields.FULLMOVE.regex()
+ )
+ );
+
+/*
+ private static final Pattern PATTERN =
+ Pattern.compile(
+ "^([pPnNbBrRqQkK1-8]+/?)* [wb] [qQkK]+|- ([a-h][36])|- [0-9]+ [1-9][0-9]*$"
+ );
+*/
+
+ private static Parser _instance = new FENParser();
+
+ private FENParser() {
+ }
+
+ public boolean isValidFen(String fen) {
+ return PATTERN.matcher(fen).matches();
+ }
+
+ @Override
+ public Position parse(String string) throws ParseException {
+ if (string == null)
+ throw new ParseException("parse.null.input.string");
+ if (!isValidFen(string))
+ throw new ParseException("parse.fen.invalid.string");
+
+ Position position = Positions.EMPTY.getPosition();
+
+ String[] fields = string.split(SPLIT_REGEX);
+
+ _parsePieces(
+ fields[FEN.Fields.PIECES.index()],
+ position
+ );
+ _parseMove(
+ fields[FEN.Fields.MOVE.index()],
+ position
+ );
+ _parseCastle(
+ fields[FEN.Fields.CASTLE.index()],
+ position
+ );
+ _parseEnPassant(
+ fields[FEN.Fields.EN_PASSANT.index()],
+ position
+ );
+ _parseHalfMove(
+ fields[FEN.Fields.HALFMOVE.index()],
+ position
+ );
+ _parseFullMove(
+ fields[FEN.Fields.FULLMOVE.index()],
+ position
+ );
+ return position;
+ }
+
+ private void _parsePieces(String fen, Position position) throws ParseException {
+ String[] lines = fen.split(LINE_REGEX);
+ if (lines.length != Square.getSize())
+ throw new ParseException("parse.fen.incorrect.board");
+ for (int i = 0; i < lines.length; ++i) {
+ int hLine = lines.length - (i + 1);
+ int vLine = 0;
+ char[] pieces = lines[i].toCharArray();
+ for (char piece : pieces) {
+ if (vLine >= Square.getSize())
+ throw new ParseException("parse.fen.incorrect.board");
+ if (Character.isDigit(piece)) {
+ int num = Character.getNumericValue(piece);
+ if (vLine + num > Square.getSize())
+ throw new ParseException("parse.fen.incorrect.board");
+ for (int j = 0; j < num; ++j) {
+ position.setPiece(
+ null,
+ Square.getSquare(vLine, hLine)
+ );
+ vLine++;
+ }
+ } else {
+ position.setPiece(
+ FEN.getColorPiece(piece),
+ Square.getSquare(vLine, hLine)
+ );
+ vLine++;
+ }
+ }
+ }
+ }
+
+ private void _parseMove(String move, Position position) {
+ position.setMove(
+ FEN.getColor(move.charAt(0))
+ );
+ }
+
+ private void _parseCastle(String castle, Position position) {
+ position.setCastle(
+ Color.WHITE,
+ FEN.getCastle(Color.WHITE, castle)
+ );
+ position.setCastle(
+ Color.BLACK,
+ FEN.getCastle(Color.BLACK, castle)
+ );
+ }
+
+ private void _parseEnPassant(String enPassant, Position position) {
+ position.setEnPassant(
+ FEN.getEnPassant(enPassant)
+ );
+ }
+
+ private void _parseHalfMove(String halfMove, Position position) {
+ position.setHalfMove(
+ Integer.parseInt(halfMove)
+ );
+ }
+
+ private void _parseFullMove(String fullMove, Position position) {
+ position.setFullMove(
+ Integer.parseInt(fullMove)
+ );
+ }
+
+ public static Parser getInstance() {
+ return _instance;
+ }
+
+ public static void main(String[] args) throws ParseException {
+
+/*
+ Pattern pattern =
+ Pattern.compile(
+ "^([pPnNbBrRqQkK1-8]+/?){8} [wb] ([qQkK]+|-) ([a-h][36]|-) [0-9]+ [1-9][0-9]*$"
+ );
+ System.out.println(
+ pattern.matcher("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - a6 0 1").matches()
+ );
+*/
+
+ Position position = getInstance().parse(
+ //"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"
+ "r7/7p/8/8/8/8/PPPPPP2/1N1Q2NR w KQkq a3 20 20"
+ );
+ System.out.println(position);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.game;
+
+import org.hedgecode.chess.position.Color;
+import org.hedgecode.chess.position.Square;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public abstract class AbstractMove implements Move {
+
+ Color color;
+ Square from, to;
+
+ protected AbstractMove(Color color, Square from, Square to) {
+ this.color = color;
+ this.from = from;
+ this.to = to;
+ }
+
+ @Override
+ public Color color() {
+ return color;
+ }
+
+ @Override
+ public Square from() {
+ return from;
+ }
+
+ @Override
+ public Square to() {
+ return to;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.game;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Game {
+
+ Moves getMoves();
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.game;
+
+import org.hedgecode.chess.position.Color;
+import org.hedgecode.chess.position.Piece;
+import org.hedgecode.chess.position.Square;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class GameMove extends AbstractMove {
+
+ protected GameMove(Color color, Square from, Square to) {
+ super(color, from, to);
+ }
+
+ @Override
+ public boolean isCapture() {
+ return false;
+ }
+
+ @Override
+ public boolean isCastle() {
+ return false;
+ }
+
+ @Override
+ public boolean isPromote() {
+ return false;
+ }
+
+ @Override
+ public Piece promote() {
+ return null;
+ }
+
+ @Override
+ public boolean isCheck() {
+ return false;
+ }
+
+ @Override
+ public boolean isMate() {
+ return false;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.game;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hedgecode.chess.position.Color;
+import org.hedgecode.chess.position.Square;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class GameMoves implements Moves {
+
+ private int moveNumber;
+ private List<Move> moves;
+
+ public GameMoves() {
+ moveNumber = -1;
+ moves = new ArrayList<>();
+ }
+
+ @Override
+ public void move(Move move) {
+
+ }
+
+ @Override
+ public Move first() {
+ if (moves.isEmpty())
+ return null;
+ moveNumber = 0;
+ return moves.get(moveNumber);
+ }
+
+ @Override
+ public Move last() {
+ if (moves.isEmpty())
+ return null;
+ moveNumber = moves.size() - 1;
+ return moves.get(moveNumber);
+ }
+
+ @Override
+ public boolean hasNext() {
+ return moves.size() > moveNumber + 1;
+ }
+
+ @Override
+ public Move next() {
+ if (hasNext())
+ return moves.get(++moveNumber);
+ return null;
+ }
+
+ @Override
+ public void clear() {
+ moveNumber = -1;
+ moves.clear();
+ }
+
+ @Override
+ public int count() {
+ return moves.size();
+ }
+
+ @Override
+ public Move byNumber(int num, Color color) {
+ return null;
+ }
+
+ static class Builder {
+
+ Move build(Color color, Square from, Square to) {
+ return new GameMove(color, from, to);
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.game;
+
+import org.hedgecode.chess.position.Color;
+import org.hedgecode.chess.position.Piece;
+import org.hedgecode.chess.position.Square;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Move {
+
+ Color color();
+
+ Square from();
+ Square to();
+
+ boolean isCapture();
+ boolean isCastle();
+
+ boolean isPromote();
+ Piece promote();
+
+ boolean isCheck();
+ boolean isMate();
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.game;
+
+import org.hedgecode.chess.position.Color;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Moves {
+
+ void move(Move move);
+
+ Move first();
+ Move last();
+
+ boolean hasNext();
+ Move next();
+
+ void clear();
+
+ int count();
+
+ Move byNumber(int num, Color color);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.hedgefish;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class HedgefishCommand {
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public String getParams() {
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.hedgefish;
+
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.DebugMode;
+import org.hedgecode.chess.uci.Transmitter;
+
+/**
+ * Hedgefish UCI Engine.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class HedgefishEngine implements Engine {
+
+ private static final String HEDGEFISH_COPYIGHT = "Hedgefish 0.1 (c) 2018 Hedgecode, D.Samoshin aka gotty";
+
+ private Transmitter<HedgefishCommand> transmitter;
+
+ private DebugMode debugMode;
+
+ HedgefishEngine() {
+ transmitter = new HedgefishTransmitter();
+ debugMode = DebugMode.OFF;
+ }
+
+ public Transmitter<HedgefishCommand> transmitter() {
+ return transmitter;
+ }
+
+ public void command(HedgefishCommand command) {
+ transmitter.addCommand(command);
+ }
+
+
+ @Override
+ public void init() {
+
+ }
+
+ @Override
+ public void debug(DebugMode mode) {
+ debugMode = mode;
+ }
+
+ @Override
+ public void isReady() {
+
+ }
+
+ @Override
+ public void go() {
+
+ }
+
+ @Override
+ public void stop() {
+
+ }
+
+ @Override
+ public void ponderhit() {
+
+ }
+
+ @Override
+ public void quit() {
+ transmitter.stop();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.hedgefish;
+
+import org.hedgecode.chess.uci.CommandExecutor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.EngineException;
+import org.hedgecode.chess.uci.EngineRunner;
+import org.hedgecode.chess.uci.Transmitter;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+
+/**
+ * Hedgefish UCI Engine Runner.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class HedgefishEngineRunner implements EngineRunner {
+
+ private HedgefishEngine engine;
+ private boolean isRunning;
+
+ HedgefishEngineRunner() {
+ engine = new HedgefishEngine();
+ isRunning = false;
+ }
+
+ @Override
+ public Engine init() throws EngineException {
+ if (isRunning)
+ throw new EngineException("uci.engine.already.run");
+ return engine;
+ }
+
+ @Override
+ public void run(final CommandExecutor commandExecutor) throws EngineException {
+ if (isRunning)
+ throw new EngineException("uci.engine.already.run");
+
+ Thread engineThread = new Thread(
+ new Runnable() {
+ public void run() {
+ try {
+ Transmitter<HedgefishCommand> engineTransmitter = engine.transmitter();
+ while (engineTransmitter.isActive()) {
+ if (engineTransmitter.hasCommand()) {
+ HedgefishCommand command = engineTransmitter.transmitCommand();
+ commandExecutor.exec(
+ command.getName(),
+ CommandDirection.FROM_ENGINE,
+ command.getParams()
+ );
+ }
+ }
+ } finally {
+ commandExecutor.exec(
+ UCIConstants.TERMINATE,
+ CommandDirection.FROM_ENGINE,
+ null
+ );
+ isRunning = false;
+ }
+ }
+ }
+ );
+ engineThread.start();
+ isRunning = true;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.hedgefish;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+import org.hedgecode.chess.uci.Transmitter;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class HedgefishTransmitter implements Transmitter<HedgefishCommand> {
+
+ private Queue<HedgefishCommand> queue;
+ private boolean isActive;
+
+ HedgefishTransmitter() {
+ queue = new LinkedList<>();
+ isActive = true;
+ }
+
+ @Override
+ public boolean isActive() {
+ return isActive && queue.isEmpty();
+ }
+
+ @Override
+ public boolean hasCommand() {
+ return !queue.isEmpty();
+ }
+
+ @Override
+ public HedgefishCommand transmitCommand() {
+ return queue.poll();
+ }
+
+ @Override
+ public void addCommand(HedgefishCommand command) {
+ if (isActive)
+ queue.add(command);
+ }
+
+ @Override
+ public void stop() {
+ isActive = false;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.hedgefish;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class Types {
+
+ public static final int MAX_MOVES = 256;
+ public static final int MAX_PLY = 128;
+
+ public enum MoveType {
+ NORMAL,
+ PROMOTION,
+ ENPASSANT,
+ CASTLING
+ }
+
+ public enum Color {
+ WHITE,
+ BLACK,
+ COLOR_NB
+ }
+
+ public enum CastlingSide {
+ KING_SIDE,
+ QUEEN_SIDE,
+ CASTLING_SIDE_NB
+ }
+
+ public enum CastlingRight {
+ NO_CASTLING,
+ WHITE_OO,
+ WHITE_OOO,
+ BLACK_OO,
+ BLACK_OOO,
+ ANY_CASTLING,
+ CASTLING_RIGHT_NB
+ }
+
+ public enum Phase {
+ PHASE_ENDGAME,
+ PHASE_MIDGAME,
+ MG,
+ EG,
+ PHASE_NB
+ }
+
+ public enum ScaleFactor {
+ SCALE_FACTOR_DRAW,
+ SCALE_FACTOR_NORMAL,
+ SCALE_FACTOR_MAX,
+ SCALE_FACTOR_NONE
+ }
+
+ public enum Bound {
+ BOUND_NONE,
+ BOUND_UPPER,
+ BOUND_LOWER,
+ BOUND_EXACT
+ }
+
+// enum Value
+
+ public enum PieceType {
+ NO_PIECE_TYPE,
+ PAWN,
+ KNIGHT,
+ BISHOP,
+ ROOK,
+ QUEEN,
+ KING,
+ ALL_PIECES,
+ PIECE_TYPE_NB
+ }
+
+ public enum Piece {
+ NO_PIECE,
+ W_PAWN, W_KNIGHT, W_BISHOP, W_ROOK, W_QUEEN, W_KING,
+ B_PAWN, B_KNIGHT, B_BISHOP, B_ROOK, B_QUEEN, B_KING,
+ PIECE_NB
+ }
+
+// ...
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.hedgefish;
+
+/**
+ * Universal Chess Interface.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class UCI {
+
+ public static class Option {
+
+ String defaultValue, currentValue, type;
+ int min, max;
+ int idx;
+// OnChange on_change;
+
+
+ public Option() {
+
+ }
+
+ public Option(boolean v) {
+
+ }
+
+ public Option(final char[] v) {
+
+ }
+
+ public Option(double v, int minv, int maxv) {
+
+ }
+
+ public Option(final char[] v, final char[] cur) {
+
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.img;
+
+import java.awt.Image;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.imageio.ImageIO;
+
+import org.hedgecode.chess.position.Position;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class DiagramBuilder implements ImageBuilder {
+
+ private static ImageBuilder _instance = new DiagramBuilder();
+
+ private DiagramBuilder() {
+ }
+
+ @Override
+ public String build(Position position) {
+
+ return "";
+ }
+
+ @Override
+ public Image build(Position position, String type) {
+ // BufferedImage
+ // Image image = ImageIO.read(new URL(urlname));
+ // Graphics.drawImage()
+
+/*
+ Image image = ImageIO.read(new File("f://image1.jpg"));
+
+ ImageIO.write(image, "JPEG", new File("f://image2.jpg"));
+*/
+
+ return null;
+ }
+
+ public static ImageBuilder getInstance() {
+ return _instance;
+ }
+
+
+ public static void main(String[] args) {
+ String[] formatNames;
+ Set<String> set = new HashSet<>();
+
+ formatNames = ImageIO.getReaderFormatNames();
+ for (String formatName : formatNames)
+ set.add(formatName.toLowerCase());
+ System.out.println("Supported read formats: " + set);
+
+ set.clear();
+
+ formatNames = ImageIO.getWriterFormatNames();
+ for (String formatName : formatNames)
+ set.add(formatName.toLowerCase());
+ System.out.println("Supported write formats: " + set);
+
+ set.clear();
+
+ formatNames = ImageIO.getReaderMIMETypes();
+ for (String formatName : formatNames)
+ set.add(formatName.toLowerCase());
+ System.out.println("Supported read MIME types: " + set);
+
+ set.clear();
+
+ formatNames = ImageIO.getWriterMIMETypes();
+ for (String formatName : formatNames)
+ set.add(formatName.toLowerCase());
+ System.out.println("Supported write MIME types: " + set);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.img;
+
+import java.awt.Image;
+
+import org.hedgecode.chess.position.Builder;
+import org.hedgecode.chess.position.Position;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface ImageBuilder extends Builder {
+
+ String build(Position position);
+
+ Image build(Position position, String type);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.img;
+
+import javax.imageio.ImageIO;
+
+/**
+ * Supported image formats for reading/writing.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum ImageFormat {
+
+ PNG ( new String[]{"png"} ),
+ GIF ( new String[]{"gif"} ),
+ JPG ( new String[]{"jpg", "jpeg"} ),
+ SVG ( new String[]{"svg"} ), // todo
+ BMP ( new String[]{"bmp", "wbmp"} );
+
+ private String[] fortmatExts;
+
+ private boolean isRead;
+ private boolean isWrite;
+
+ ImageFormat(String[] exts) {
+ fortmatExts = exts;
+ isRead = isExist(
+ ImageIO.getReaderFormatNames(), fortmatExts
+ );
+ isWrite = isExist(
+ ImageIO.getWriterFormatNames(), fortmatExts
+ );
+ }
+
+ public String getExt() {
+ return fortmatExts[0];
+ }
+
+ public String[] getExts() {
+ return fortmatExts;
+ }
+
+ public boolean isRead() {
+ return isRead;
+ }
+
+ public boolean isWrite() {
+ return isWrite;
+ }
+
+ public static ImageFormat findFormat(String formatName) {
+ if (formatName != null) {
+ for (ImageFormat imageFormat : ImageFormat.values()) {
+ if (isExist(imageFormat.getExts(), formatName))
+ return imageFormat;
+ }
+ }
+ return null;
+ }
+
+ private static boolean isExist(String[] names, String... args) {
+ for (String arg : args) {
+ for (String name : names) {
+ if (arg.equalsIgnoreCase(name))
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+/*
+ public static void main(String[] args) {
+ ImageFormat imageFormat = JPG;
+ System.out.println("Supported format: " + imageFormat);
+ imageFormat = findFormat("jpeg");
+ imageFormat = findFormat("svg");
+ imageFormat = findFormat("jpeeg");
+ }
+*/
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.pgn;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class PGNBuilder {
+
+
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.pgn;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class PGNParser {
+
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.position;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Builder {
+
+ String build(Position position);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.position;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum Castle {
+
+ NONE,
+ KING,
+ QUEEN,
+ BOTH
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.position;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum Color {
+
+ WHITE,
+ BLACK
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.position;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum ColorPiece {
+
+ WHITE_PAWN (Color.WHITE, Piece.PAWN),
+ WHITE_KNIGHT (Color.WHITE, Piece.KNIGHT),
+ WHITE_BISHOP (Color.WHITE, Piece.BISHOP),
+ WHITE_ROOK (Color.WHITE, Piece.ROOK),
+ WHITE_QUEEN (Color.WHITE, Piece.QUEEN),
+ WHITE_KING (Color.WHITE, Piece.KING),
+
+ BLACK_PAWN (Color.BLACK, Piece.PAWN),
+ BLACK_KNIGHT (Color.BLACK, Piece.KNIGHT),
+ BLACK_BISHOP (Color.BLACK, Piece.BISHOP),
+ BLACK_ROOK (Color.BLACK, Piece.ROOK),
+ BLACK_QUEEN (Color.BLACK, Piece.QUEEN),
+ BLACK_KING (Color.BLACK, Piece.KING);
+
+ private Color color;
+ private Piece piece;
+
+ ColorPiece(Color color, Piece piece) {
+ this.color = color;
+ this.piece = piece;
+ }
+
+ public Color color() {
+ return color;
+ }
+
+ public Piece piece() {
+ return piece;
+ }
+
+ public static ColorPiece getColorPiece(Color color, Piece piece) {
+ if (color == null || piece == null)
+ return null;
+ for (ColorPiece colorPiece : ColorPiece.values()) {
+ if (colorPiece.color.equals(color) && (colorPiece.piece.equals(piece)))
+ return colorPiece;
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.position;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class DiagramPosition implements Position {
+
+ protected final Map<Square, ColorPiece> squares = new HashMap<Square, ColorPiece>() {
+ {
+ put(Square.A1, null); put(Square.B1, null); put(Square.C1, null); put(Square.D1, null);
+ put(Square.E1, null); put(Square.F1, null); put(Square.G1, null); put(Square.H1, null);
+ put(Square.A2, null); put(Square.B2, null); put(Square.C2, null); put(Square.D2, null);
+ put(Square.E2, null); put(Square.F2, null); put(Square.G2, null); put(Square.H2, null);
+ put(Square.A3, null); put(Square.B3, null); put(Square.C3, null); put(Square.D3, null);
+ put(Square.E3, null); put(Square.F3, null); put(Square.G3, null); put(Square.H3, null);
+ put(Square.A4, null); put(Square.B4, null); put(Square.C4, null); put(Square.D4, null);
+ put(Square.E4, null); put(Square.F4, null); put(Square.G4, null); put(Square.H4, null);
+ put(Square.A5, null); put(Square.B5, null); put(Square.C5, null); put(Square.D5, null);
+ put(Square.E5, null); put(Square.F5, null); put(Square.G5, null); put(Square.H5, null);
+ put(Square.A6, null); put(Square.B6, null); put(Square.C6, null); put(Square.D6, null);
+ put(Square.E6, null); put(Square.F6, null); put(Square.G6, null); put(Square.H6, null);
+ put(Square.A7, null); put(Square.B7, null); put(Square.C7, null); put(Square.D7, null);
+ put(Square.E7, null); put(Square.F7, null); put(Square.G7, null); put(Square.H7, null);
+ put(Square.A8, null); put(Square.B8, null); put(Square.C8, null); put(Square.D8, null);
+ put(Square.E8, null); put(Square.F8, null); put(Square.G8, null); put(Square.H8, null);
+ }
+ };
+
+ private Color move;
+
+ @Override
+ public Map<Square, ColorPiece> getSquares() {
+ return squares;
+ }
+
+ @Override
+ public Map<Square, ColorPiece> getSquarePieces(Color color) {
+ return getSquarePieces(color, null);
+ }
+
+ @Override
+ public Map<Square, ColorPiece> getSquarePieces(Color color, Piece piece) {
+ Map<Square, ColorPiece> squarePieces = new HashMap<>();
+ for (Map.Entry<Square, ColorPiece> entry : squares.entrySet()) {
+ Square square = entry.getKey();
+ ColorPiece colorPiece = entry.getValue();
+ if (colorPiece != null) {
+ if (color == null || color.equals(colorPiece.color()))
+ if (piece == null || piece.equals(colorPiece.piece()))
+ squarePieces.put(square, colorPiece);
+ }
+ }
+ return squarePieces;
+ }
+
+ @Override
+ public void setPiece(Color color, Piece piece, Square square) {
+ squares.put(square, ColorPiece.getColorPiece(color, piece));
+ }
+
+ @Override
+ public void setPiece(ColorPiece colorPiece, Square square) {
+ squares.put(square, colorPiece);
+ }
+
+ @Override
+ public Color getMove() {
+ return move;
+ }
+
+ @Override
+ public void setMove(Color color) {
+ move = color;
+ }
+
+ @Override
+ public boolean isDiagram() {
+ return true;
+ }
+
+ @Override
+ public Castle getCastle(Color color) {
+ return Castle.NONE;
+ }
+
+ @Override
+ public void setCastle(Color color, Castle castle) {
+ // do not supported in this class
+ }
+
+ @Override
+ public Square getEnPassant() {
+ return null;
+ }
+
+ @Override
+ public void setEnPassant(Square square) {
+ // do not supported in this class
+ }
+
+ @Override
+ public int getHalfMove() {
+ return 0;
+ }
+
+ @Override
+ public void setHalfMove(int count) {
+ // do not supported in this class
+ }
+
+ @Override
+ public int getFullMove() {
+ return 0;
+ }
+
+ @Override
+ public void setFullMove(int number) {
+ // do not supported in this class
+ }
+
+ @Override
+ public void clear() {
+ for (Square square : Square.values()) {
+ squares.put(square, null);
+ }
+ }
+
+ @Override
+ public void initial() {
+ PositionBuilder.buildInitial(
+ this
+ );
+ }
+
+ static class PositionBuilder {
+
+ public static void buildInitial(Position position) {
+ position.clear();
+
+ Map<Square, ColorPiece> squares = position.getSquares();
+
+ squares.put(Square.A1, ColorPiece.WHITE_ROOK);
+ squares.put(Square.B1, ColorPiece.WHITE_KNIGHT);
+ squares.put(Square.C1, ColorPiece.WHITE_BISHOP);
+ squares.put(Square.D1, ColorPiece.WHITE_QUEEN);
+ squares.put(Square.E1, ColorPiece.WHITE_KING);
+ squares.put(Square.F1, ColorPiece.WHITE_BISHOP);
+ squares.put(Square.G1, ColorPiece.WHITE_KNIGHT);
+ squares.put(Square.H1, ColorPiece.WHITE_ROOK);
+
+ squares.put(Square.A8, ColorPiece.BLACK_ROOK);
+ squares.put(Square.B8, ColorPiece.BLACK_KNIGHT);
+ squares.put(Square.C8, ColorPiece.BLACK_BISHOP);
+ squares.put(Square.D8, ColorPiece.BLACK_QUEEN);
+ squares.put(Square.E8, ColorPiece.BLACK_KING);
+ squares.put(Square.F8, ColorPiece.BLACK_BISHOP);
+ squares.put(Square.G8, ColorPiece.BLACK_KNIGHT);
+ squares.put(Square.H8, ColorPiece.BLACK_ROOK);
+
+ for (Square square : Square.values()) {
+ if (square.getH() == Square.A2.getH())
+ squares.put(square, ColorPiece.WHITE_PAWN);
+ else if (square.getH() == Square.A7.getH())
+ squares.put(square, ColorPiece.BLACK_PAWN);
+ }
+
+ position.setMove(Color.WHITE);
+ position.setCastle(Color.WHITE, Castle.BOTH);
+ position.setCastle(Color.BLACK, Castle.BOTH);
+ position.setEnPassant(null);
+ position.setHalfMove(0);
+ position.setFullMove(1);
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.position;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class GamePosition extends DiagramPosition {
+
+ private Map<Color, Castle> castles = new HashMap<Color, Castle>(){
+ {
+ put(Color.WHITE, Castle.NONE);
+ put(Color.BLACK, Castle.NONE);
+ }
+ };
+
+ private int halfMove;
+ private int fullMove;
+
+ private Square enPassant;
+
+ @Override
+ public boolean isDiagram() {
+ return false;
+ }
+
+ @Override
+ public Castle getCastle(Color color) {
+ return castles.get(color);
+ }
+
+ @Override
+ public void setCastle(Color color, Castle castle) {
+ castles.put(color, castle);
+ }
+
+ @Override
+ public Square getEnPassant() {
+ return enPassant;
+ }
+
+ @Override
+ public void setEnPassant(Square square) {
+ enPassant = square;
+ }
+
+ @Override
+ public int getHalfMove() {
+ return halfMove;
+ }
+
+ @Override
+ public void setHalfMove(int count) {
+ halfMove = count;
+ }
+
+ @Override
+ public int getFullMove() {
+ return fullMove;
+ }
+
+ @Override
+ public void setFullMove(int number) {
+ fullMove = number;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.position;
+
+import java.util.ResourceBundle;
+
+import org.hedgecode.chess.ChessHogConstants;
+
+/**
+ * Incorrect parsing chess diagram/game Exception.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class ParseException extends Exception {
+
+ private static final ResourceBundle LOCALE_BUNDLE =
+ ResourceBundle.getBundle(ChessHogConstants.LOCALE_BUNDLE_FILE);
+
+ private String localeKey;
+ private String message;
+
+ public ParseException(String localeKey) {
+ this.localeKey = localeKey;
+ this.message = null;
+ }
+
+ public ParseException(String localeKey, String message) {
+ this.localeKey = localeKey;
+ this.message = message;
+ }
+
+ public String getLocaleKey() {
+ return localeKey;
+ }
+
+ public String getMessage() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(LOCALE_BUNDLE.getString(localeKey));
+ if (message != null)
+ sb.append(": [").append(message).append("]");
+ return message;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.position;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Parser {
+
+ Position parse(String string) throws ParseException;
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.position;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum Piece {
+
+ PAWN ('p'),
+ KNIGHT ('n'),
+ BISHOP ('b'),
+ ROOK ('r'),
+ QUEEN ('q'),
+ KING ('k');
+
+ private char letter;
+
+ Piece(char letter) {
+ this.letter = letter;
+ }
+
+ public char letter() {
+ return letter;
+ }
+
+ public static Piece byLetter(char letter) {
+ for (Piece piece : Piece.values()) {
+ if (piece.letter() == letter)
+ return piece;
+ }
+ return null;
+ }
+
+ public static Piece byLetter(String letter) {
+ if (letter == null || letter.length() != 1)
+ return null;
+ for (Piece piece : Piece.values()) {
+ if (piece.letter() == letter.charAt(0))
+ return piece;
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.position;
+
+import java.util.Map;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Position {
+
+ Map<Square, ColorPiece> getSquares();
+
+ Map<Square, ColorPiece> getSquarePieces(Color color);
+
+ Map<Square, ColorPiece> getSquarePieces(Color color, Piece piece);
+
+ void setPiece(Color color, Piece piece, Square square);
+
+ void setPiece(ColorPiece colorPiece, Square square);
+
+ Color getMove();
+
+ void setMove(Color color);
+
+ boolean isDiagram();
+
+ Castle getCastle(Color color);
+
+ void setCastle(Color color, Castle castle);
+
+ Square getEnPassant();
+
+ void setEnPassant(Square square);
+
+ int getHalfMove();
+
+ void setHalfMove(int count);
+
+ int getFullMove();
+
+ void setFullMove(int number);
+
+ void initial();
+
+ void clear();
+
+ default void setPawn(Color color, Square square) {
+ setPiece(color, Piece.PAWN, square);
+ }
+
+ default void setPawns(Color color, Square... squares) {
+ for(Square square : squares)
+ setPiece(color, Piece.PAWN, square);
+ }
+
+ default void setKnight(Color color, Square square) {
+ setPiece(color, Piece.KNIGHT, square);
+ }
+
+ default void setBishop(Color color, Square square) {
+ setPiece(color, Piece.BISHOP, square);
+ }
+
+ default void setRook(Color color, Square square) {
+ setPiece(color, Piece.ROOK, square);
+ }
+
+ default void setQueen(Color color, Square square) {
+ setPiece(color, Piece.QUEEN, square);
+ }
+
+ default void setKing(Color color, Square square) {
+ setPiece(color, Piece.KING, square);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.position;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum PositionType {
+
+ DIAGRAM,
+ GAME
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.position;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum Positions {
+
+ INITIAL {
+ @Override
+ public Position getPosition() {
+ Position position = FACTORY.create();
+ position.initial();
+ return position;
+ }
+ },
+
+ EMPTY {
+ @Override
+ public Position getPosition() {
+ Position position = FACTORY.create();
+ position.clear();
+ return position;
+ }
+ };
+
+ public abstract Position getPosition();
+
+ static class Factory {
+
+ private Factory() {
+ }
+
+ Position create() {
+ return create(
+ PositionType.GAME
+ );
+ }
+
+ Position create(PositionType type) {
+ Position position;
+ switch (type) {
+ case DIAGRAM:
+ position = new DiagramPosition();
+ break;
+ case GAME:
+ default:
+ position = new GamePosition();
+ }
+ return position;
+ }
+
+ }
+
+ private static final Factory FACTORY = new Factory();
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.position;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum Square {
+
+ A1 (0, 0), B1 (1, 0), C1 (2, 0), D1 (3, 0), E1 (4, 0), F1 (5, 0), G1 (6, 0), H1 (7, 0),
+ A2 (0, 1), B2 (1, 1), C2 (2, 1), D2 (3, 1), E2 (4, 1), F2 (5, 1), G2 (6, 1), H2 (7, 1),
+ A3 (0, 2), B3 (1, 2), C3 (2, 2), D3 (3, 2), E3 (4, 2), F3 (5, 2), G3 (6, 2), H3 (7, 2),
+ A4 (0, 3), B4 (1, 3), C4 (2, 3), D4 (3, 3), E4 (4, 3), F4 (5, 3), G4 (6, 3), H4 (7, 3),
+ A5 (0, 4), B5 (1, 4), C5 (2, 4), D5 (3, 4), E5 (4, 4), F5 (5, 4), G5 (6, 4), H5 (7, 4),
+ A6 (0, 5), B6 (1, 5), C6 (2, 5), D6 (3, 5), E6 (4, 5), F6 (5, 5), G6 (6, 5), H6 (7, 5),
+ A7 (0, 6), B7 (1, 6), C7 (2, 6), D7 (3, 6), E7 (4, 6), F7 (5, 6), G7 (6, 6), H7 (7, 6),
+ A8 (0, 7), B8 (1, 7), C8 (2, 7), D8 (3, 7), E8 (4, 7), F8 (5, 7), G8 (6, 7), H8 (7, 7);
+
+ private static final int SIZE = 8;
+
+ private int vertical;
+ private int horizontal;
+
+ Square(int vLine, int hLine) {
+ this.vertical = vLine;
+ this.horizontal = hLine;
+ }
+
+ public int getV() {
+ return vertical;
+ }
+
+ public int getH() {
+ return horizontal;
+ }
+
+ public static Square getSquare(int vLine, int hLine) {
+ for (Square square : Square.values()) {
+ if (square.getV() == vLine && square.getH() == hLine)
+ return square;
+ }
+ return null;
+ }
+
+ public static Square getSquare(String squareName) {
+ for (Square square : Square.values()) {
+ if (square.name().equalsIgnoreCase(squareName))
+ return square;
+ }
+ return null;
+ }
+
+ public static int getSize() {
+ return SIZE;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.tcd;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Tiny Chess Diagram (TCD) constants.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class TCD {
+
+ public static final byte BYTE_MASK = 0b01000000;
+ public static final byte FRAME_MASK = 0b111;
+ public static final byte FRAME_LENGTH = 3;
+
+ public static final byte WHITE = 0b000;
+ public static final byte BLACK = 0b111;
+
+ public static final byte END = 0b111;
+
+ public static final byte PAWN = 0b001;
+ public static final byte KNIGHT = 0b010;
+ public static final byte BISHOP = 0b011;
+ public static final byte ROOK = 0b100;
+ public static final byte QUEEN = 0b101;
+ public static final byte KING = 0b110;
+
+ private static final byte SQUARE_A = 0b000, SQUARE_1 = SQUARE_A;
+ private static final byte SQUARE_B = 0b001, SQUARE_2 = SQUARE_B;
+ private static final byte SQUARE_C = 0b010, SQUARE_3 = SQUARE_C;
+ private static final byte SQUARE_D = 0b011, SQUARE_4 = SQUARE_D;
+ private static final byte SQUARE_E = 0b100, SQUARE_5 = SQUARE_E;
+ private static final byte SQUARE_F = 0b101, SQUARE_6 = SQUARE_F;
+ private static final byte SQUARE_G = 0b110, SQUARE_7 = SQUARE_G;
+ private static final byte SQUARE_H = 0b111, SQUARE_8 = SQUARE_H;
+
+ public static final byte SQUARE_SIZE = 8;
+
+ public static final byte[][] SQUARE = {
+ {SQUARE_A, SQUARE_1},
+ {SQUARE_B, SQUARE_2},
+ {SQUARE_C, SQUARE_3},
+ {SQUARE_D, SQUARE_4},
+ {SQUARE_E, SQUARE_5},
+ {SQUARE_F, SQUARE_6},
+ {SQUARE_G, SQUARE_7},
+ {SQUARE_H, SQUARE_8},
+ };
+
+ public static final byte MOVE = 0b001;
+
+ public static final byte CASTLE_WHITE = 0b000;
+ public static final byte CASTLE_BLACK = 0b111;
+
+ public static final byte CASTLE_NONE = 0b000;
+ public static final byte CASTLE_KING = 0b001;
+ public static final byte CASTLE_QUEEN = 0b010;
+ public static final byte CASTLE_BOTH = 0b011;
+
+ public static final byte[] CASTLE_OPTS = {CASTLE_NONE, CASTLE_KING, CASTLE_QUEEN, CASTLE_BOTH};
+
+ public static final byte EN_PASSANT = 0b100;
+
+ public static final byte HALFMOVE = 0b010;
+ public static final byte FULLMOVE = 0b011;
+
+ public static final byte MIN_BYTE = 0x40;
+ public static final byte MAX_BYTE = 0x7F;
+
+ private static final byte[] REPLACE_TO =
+ {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x2B, 0x2D};
+ private static final byte[] REPLACE_FROM =
+ {0x40, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F};
+
+ public static final Charset OUTPUT_CHARSET = StandardCharsets.US_ASCII;
+
+ private static boolean onlyDiagram = true;
+
+ private TCD() {
+ }
+
+ public static void setDiagram(boolean isDiagram) {
+ onlyDiagram = isDiagram;
+ }
+
+ public static boolean isDiagram() {
+ return onlyDiagram;
+ }
+
+ public static void replaceTo(byte[] bytes) {
+ for (int i = 0; i < bytes.length; ++i) {
+ int j = frameSearch(REPLACE_FROM, bytes[i]);
+ if (j >= 0)
+ bytes[i] = REPLACE_TO[j];
+ }
+ }
+
+ public static void replaceFrom(byte[] bytes) {
+ for (int i = 0; i < bytes.length; ++i) {
+ int j = frameSearch(REPLACE_TO, bytes[i]);
+ if (j >= 0)
+ bytes[i] = REPLACE_FROM[j];
+ }
+ }
+
+ public static boolean isValid(byte[] bytes) {
+ if (bytes.length < 1)
+ return false;
+ for (byte bite : bytes) {
+ if (bite < MIN_BYTE)
+ return false;
+ }
+ return true;
+ }
+
+ public static boolean isColor(byte frame) {
+ return frame == WHITE || frame == BLACK;
+ }
+
+ public static boolean isNotColor(byte frame) {
+ return !isColor(frame);
+ }
+
+ public static boolean isWhiteBlack(byte first, byte second) {
+ return first == WHITE && second == BLACK;
+ }
+
+ public static boolean isBlackWhite(byte first, byte second) {
+ return isWhiteBlack(second, first);
+ }
+
+ public static boolean isNotCastle(byte frame) {
+ return frameSearch(CASTLE_OPTS, frame) < 0;
+ }
+
+ private static int frameSearch(byte[] bytes, byte frame) {
+ for (int i = 0; i < bytes.length; ++i)
+ if (bytes[i] == frame)
+ return i;
+ return -1;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.tcd;
+
+import java.util.Map;
+
+import org.hedgecode.chess.Builders;
+import org.hedgecode.chess.Parsers;
+import org.hedgecode.chess.position.Builder;
+import org.hedgecode.chess.position.Castle;
+import org.hedgecode.chess.position.Color;
+import org.hedgecode.chess.position.ColorPiece;
+import org.hedgecode.chess.position.ParseException;
+import org.hedgecode.chess.position.Piece;
+import org.hedgecode.chess.position.Position;
+import org.hedgecode.chess.position.Positions;
+import org.hedgecode.chess.position.Square;
+
+/**
+ * Tiny Chess Diagram (TCD) builder.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class TCDBuilder implements Builder {
+
+ private static final byte[] EMPTY = {};
+
+ private static Builder _instance = new TCDBuilder();
+
+ private TCDBuilder() {
+ }
+
+ @Override
+ public String build(Position position) {
+ return _build(
+ position
+ );
+ }
+
+ private String _build(Position position) {
+ // todo: isInitial
+ byte[] white = _buildColor(Color.WHITE, position);
+ byte[] black = _buildColor(Color.BLACK, position);
+ byte[] addition = _buildAddition(position);
+
+ byte[] bytes;
+ int length = white.length + black.length + addition.length;
+ if (length % 2 == 0) {
+ bytes = _concat(white, black, addition);
+ } else {
+ byte[] end = {TCD.END};
+ bytes = _concat(white, black, addition, end);
+ }
+
+ bytes = _compress(bytes);
+ TCD.replaceTo(bytes);
+
+ return new String(
+ bytes, TCD.OUTPUT_CHARSET
+ );
+ }
+
+ private byte[] _buildColor(Color color, Position position) {
+ byte[] bytes = {Color.WHITE.equals(color) ? TCD.WHITE : TCD.BLACK};
+ for (Piece piece : Piece.values()) {
+ Map<Square, ColorPiece> squarePieces = position.getSquarePieces(color, piece);
+ if (!squarePieces.isEmpty()) {
+ byte[] pieces = new byte[2 * (squarePieces.size() + 1)];
+ int i = 0;
+ switch (piece) {
+ case PAWN:
+ pieces[i++] = TCD.PAWN;
+ break;
+ case KNIGHT:
+ pieces[i++] = TCD.KNIGHT;
+ break;
+ case BISHOP:
+ pieces[i++] = TCD.BISHOP;
+ break;
+ case ROOK:
+ pieces[i++] = TCD.ROOK;
+ break;
+ case QUEEN:
+ pieces[i++] = TCD.QUEEN;
+ break;
+ case KING:
+ pieces[i++] = TCD.KING;
+ break;
+ }
+ pieces[i++] = (byte) (squarePieces.size() - 1);
+ for (Square square : squarePieces.keySet()) {
+ pieces[i++] = (byte) square.getV();
+ pieces[i++] = (byte) square.getH();
+ }
+ bytes = _concat(bytes, pieces);
+ }
+ }
+ return bytes;
+ }
+
+ private byte[] _buildAddition(Position position) {
+ byte[] bytes = {TCD.WHITE, TCD.BLACK};
+ if (!TCD.isDiagram() && !position.isDiagram()) {
+ bytes = _concat(
+ bytes,
+ _buildMove(position),
+ _buildCastle(Color.WHITE, position),
+ _buildCastle(Color.BLACK, position),
+ _buildEnPassant(position),
+ _buildHalfMove(position),
+ _buildFullMove(position)
+ );
+ }
+ return bytes;
+ }
+
+ private byte[] _buildMove(Position position) {
+ if (position.getMove() != null) {
+ return new byte[] {
+ TCD.MOVE,
+ Color.WHITE.equals(position.getMove()) ? TCD.WHITE : TCD.BLACK
+ };
+ }
+ return EMPTY;
+ }
+
+ private byte[] _buildCastle(Color color, Position position) {
+ Castle castle = position.getCastle(color);
+ if (castle != null) {
+ byte castleByte;
+ switch (castle) {
+ case KING:
+ castleByte = TCD.CASTLE_KING;
+ break;
+ case QUEEN:
+ castleByte = TCD.CASTLE_QUEEN;
+ break;
+ case BOTH:
+ castleByte = TCD.CASTLE_BOTH;
+ break;
+ default:
+ castleByte = TCD.CASTLE_NONE;
+ }
+ return new byte[] {
+ Color.WHITE.equals(color) ? TCD.CASTLE_WHITE : TCD.CASTLE_BLACK,
+ castleByte
+ };
+ }
+ return EMPTY;
+ }
+
+ private byte[] _buildEnPassant(Position position) {
+ Square square = position.getEnPassant();
+ if (square != null) {
+ return new byte[] {
+ TCD.EN_PASSANT,
+ (byte) square.getV(),
+ (byte) square.getH()
+ };
+ }
+ return EMPTY;
+ }
+
+ private byte[] _buildHalfMove(Position position) {
+ int halfMove = position.getHalfMove();
+ return new byte[] {
+ TCD.HALFMOVE,
+ (byte) (halfMove >> 2 * TCD.FRAME_LENGTH & TCD.FRAME_MASK),
+ (byte) (halfMove >> TCD.FRAME_LENGTH & TCD.FRAME_MASK),
+ (byte) (halfMove & TCD.FRAME_MASK)
+ };
+ }
+
+ private byte[] _buildFullMove(Position position) {
+ int fullMove = position.getFullMove();
+ return new byte[] {
+ TCD.FULLMOVE,
+ (byte) (fullMove >> 2 * TCD.FRAME_LENGTH & TCD.FRAME_MASK),
+ (byte) (fullMove >> TCD.FRAME_LENGTH & TCD.FRAME_MASK),
+ (byte) (fullMove & TCD.FRAME_MASK),
+ };
+ }
+
+ private byte[] _concat(byte[]... byteArrays) {
+ int length = 0;
+ for (byte[] bytes : byteArrays) {
+ length += bytes.length;
+ }
+ byte[] concatBytes = new byte[length];
+ length = 0;
+ for (byte[] bytes : byteArrays) {
+ if (bytes.length == 0)
+ continue;
+ System.arraycopy(bytes, 0, concatBytes, length, bytes.length);
+ length += bytes.length;
+ }
+ return concatBytes;
+ }
+
+ private byte[] _compress(byte[] bytes) {
+ byte[] cmpBytes = new byte[bytes.length / 2];
+ byte high, low;
+ int i = 0;
+ for (int j = 0; j < cmpBytes.length; ++j) {
+ high = (byte) ((bytes[i++] & TCD.FRAME_MASK) << TCD.FRAME_LENGTH);
+ low = (byte) (bytes[i++] & TCD.FRAME_MASK);
+ cmpBytes[j] = (byte) (TCD.BYTE_MASK | high | low);
+ }
+ return cmpBytes;
+ }
+
+ public static Builder getInstance() {
+ return _instance;
+ }
+
+
+ public static void main(String[] args) throws ParseException {
+ Position position = Positions.EMPTY.getPosition();
+
+/*
+ position.setKing(Color.WHITE, Square.C1);
+ position.setQueen(Color.WHITE, Square.B3);
+ position.setRook(Color.WHITE, Square.D1);
+ position.setBishop(Color.WHITE, Square.G5);
+ position.setPawn(Color.WHITE, Square.A2);
+ position.setPawn(Color.WHITE, Square.B2);
+ position.setPawn(Color.WHITE, Square.C2);
+ position.setPawn(Color.WHITE, Square.E4);
+ position.setPawn(Color.WHITE, Square.F2);
+ position.setPawn(Color.WHITE, Square.G2);
+ position.setPawn(Color.WHITE, Square.H2);
+
+ position.setKing(Color.BLACK, Square.E8);
+ position.setQueen(Color.BLACK, Square.E6);
+ position.setRook(Color.BLACK, Square.H8);
+ position.setBishop(Color.BLACK, Square.F8);
+ position.setKnight(Color.BLACK, Square.D7);
+ position.setPawn(Color.BLACK, Square.A7);
+ position.setPawn(Color.BLACK, Square.E5);
+ position.setPawn(Color.BLACK, Square.F7);
+ position.setPawn(Color.BLACK, Square.G7);
+ position.setPawn(Color.BLACK, Square.H7);
+*/
+
+/*
+ position.setKing(Color.WHITE, Square.G1);
+ position.setQueen(Color.WHITE, Square.A4);
+ position.setRook(Color.WHITE, Square.D1);
+ position.setBishop(Color.WHITE, Square.A3);
+ position.setBishop(Color.WHITE, Square.D3);
+ position.setPawn(Color.WHITE, Square.A2);
+ position.setPawn(Color.WHITE, Square.C3);
+ position.setPawn(Color.WHITE, Square.F6);
+ position.setPawn(Color.WHITE, Square.F2);
+ position.setPawn(Color.WHITE, Square.G2);
+ position.setPawn(Color.WHITE, Square.H2);
+
+ position.setKing(Color.BLACK, Square.E8);
+ position.setQueen(Color.BLACK, Square.F3);
+ position.setRook(Color.BLACK, Square.B8);
+ position.setRook(Color.BLACK, Square.G8);
+ position.setBishop(Color.BLACK, Square.B7);
+ position.setBishop(Color.BLACK, Square.B6);
+ position.setKnight(Color.BLACK, Square.E7);
+ position.setPawn(Color.BLACK, Square.A7);
+ position.setPawn(Color.BLACK, Square.C7);
+ position.setPawn(Color.BLACK, Square.D7);
+ position.setPawn(Color.BLACK, Square.F7);
+ position.setPawn(Color.BLACK, Square.H7);
+*/
+
+ position.setKing(Color.WHITE, Square.H1);
+ position.setQueen(Color.WHITE, Square.E3);
+ position.setRook(Color.WHITE, Square.E1);
+ position.setRook(Color.WHITE, Square.G1);
+ position.setBishop(Color.WHITE, Square.D2);
+ position.setBishop(Color.WHITE, Square.G2);
+ position.setKnight(Color.WHITE, Square.B1);
+ position.setPawn(Color.WHITE, Square.A2);
+ position.setPawn(Color.WHITE, Square.B2);
+ position.setPawn(Color.WHITE, Square.D4);
+ position.setPawn(Color.WHITE, Square.G3);
+ position.setPawn(Color.WHITE, Square.H3);
+
+ position.setKing(Color.BLACK, Square.G8);
+ position.setQueen(Color.BLACK, Square.D7);
+ position.setRook(Color.BLACK, Square.F5);
+ position.setRook(Color.BLACK, Square.F2);
+ position.setBishop(Color.BLACK, Square.D6);
+ position.setBishop(Color.BLACK, Square.D3);
+ position.setPawn(Color.BLACK, Square.A6);
+ position.setPawn(Color.BLACK, Square.B4);
+ position.setPawn(Color.BLACK, Square.D5);
+ position.setPawn(Color.BLACK, Square.E6);
+ position.setPawn(Color.BLACK, Square.E4);
+ position.setPawn(Color.BLACK, Square.G7);
+ position.setPawn(Color.BLACK, Square.H6);
+
+/*
+ position.setKing(Color.WHITE, Square.H5);
+ position.setPawn(Color.WHITE, Square.C6);
+ position.setKing(Color.BLACK, Square.A6);
+ position.setPawn(Color.BLACK, Square.F6);
+ position.setPawn(Color.BLACK, Square.G7);
+ position.setPawn(Color.BLACK, Square.H6);
+*/
+
+
+ position.setMove(Color.WHITE);
+
+ position.setCastle(Color.WHITE, Castle.NONE);
+ position.setCastle(Color.BLACK, Castle.NONE);
+
+ //position.setEnPassant(Square.A3);
+
+ position.setHalfMove(0);
+ position.setFullMove(26);
+
+ TCD.setDiagram(false);
+
+ String tcd = getInstance().build(position);
+
+ System.out.println(
+ tcd
+ );
+
+ Position tcdPosition = Parsers.TCD.parser().parse(tcd);
+
+ System.out.println(
+ Builders.ASCII.builder().build(tcdPosition)
+ );
+
+ System.out.println(
+ getInstance().build(tcdPosition)
+ );
+
+ System.out.println(
+ Builders.FEN.builder().build(tcdPosition)
+ );
+
+/*
+ System.out.println(
+ getInstance().build(Positions.INITIAL.getPosition())
+ );
+*/
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.tcd;
+
+import org.hedgecode.chess.position.Castle;
+import org.hedgecode.chess.position.Color;
+import org.hedgecode.chess.position.ParseException;
+import org.hedgecode.chess.position.Parser;
+import org.hedgecode.chess.position.Position;
+import org.hedgecode.chess.position.Positions;
+import org.hedgecode.chess.position.Square;
+
+/**
+ * Tiny Chess Diagram (TCD) parser.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class TCDParser implements Parser {
+
+ private static Parser _instance = new TCDParser();
+
+ private TCDParser() {
+ }
+
+ private final class TCDIterator {
+
+ private byte[] bytes;
+ private int pos;
+ private boolean isHighPart;
+
+ TCDIterator(byte[] bytes) {
+ this.bytes = bytes;
+ this.pos = 0;
+ this.isHighPart = true;
+ }
+
+ boolean hasNext() {
+ return (bytes.length > pos + 1) || (isHighPart && bytes.length > pos);
+ }
+
+ boolean isLast() {
+ return !isHighPart && (bytes.length - 1 == pos);
+ }
+
+ byte next() throws ParseException {
+ isHighPart = !isHighPart;
+ if (isHighPart)
+ pos++;
+ return current();
+ }
+
+ byte current() throws ParseException {
+ if (bytes.length <= pos)
+ throw new ParseException("parse.tcd.index.out.of.bounds");
+ byte frame = bytes[pos];
+ if (isHighPart)
+ frame = (byte) (frame >> TCD.FRAME_LENGTH);
+ return (byte) (frame & TCD.FRAME_MASK);
+ }
+ }
+
+ @Override
+ public Position parse(String string) throws ParseException {
+ return parse(
+ string.getBytes()
+ );
+ }
+
+ public Position parse(byte[] bytes) throws ParseException {
+ TCD.replaceFrom(bytes);
+ if (!TCD.isValid(bytes))
+ throw new ParseException("parse.tcd.invalid.bytes");
+ TCDIterator iterator = new TCDIterator(bytes);
+ return _parse(iterator);
+ }
+
+ private Position _parse(TCDIterator iterator) throws ParseException {
+ Position position;
+
+ byte curr = iterator.current();
+ byte next = iterator.next();
+
+ if (TCD.isBlackWhite(curr, next)) {
+ position = Positions.INITIAL.getPosition();
+ curr = iterator.next();
+ next = iterator.next();
+ } else {
+ position = Positions.EMPTY.getPosition();
+ boolean isWhiteAssigned = false, isBlackAssigned = false;
+ while (!isWhiteAssigned || !isBlackAssigned) {
+ switch (curr) {
+ case TCD.WHITE:
+ _parsePieces(Color.WHITE, position, iterator);
+ isWhiteAssigned = true;
+ break;
+ case TCD.BLACK:
+ _parsePieces(Color.BLACK, position, iterator);
+ isBlackAssigned = true;
+ break;
+ default:
+ throw new ParseException("parse.tcd.incorrect.color");
+ }
+ curr = iterator.current();
+ next = iterator.next();
+ }
+ }
+
+ if (!TCD.isWhiteBlack(curr, next))
+ throw new ParseException("parse.tcd.incorrect.end");
+
+ _parseAddition(position, iterator);
+
+ return position;
+ }
+
+ private void _parsePieces(Color color, Position position, TCDIterator iterator) throws ParseException {
+ byte piece = iterator.current();
+ while (TCD.isNotColor(piece)) {
+ int pieceCount = iterator.next() + 1;
+ for (int i = 0; i < pieceCount; ++i) {
+ Square square = _parseSquare(iterator);
+ switch (piece) {
+ case TCD.PAWN:
+ position.setPawn(color, square);
+ break;
+ case TCD.KNIGHT:
+ position.setKnight(color, square);
+ break;
+ case TCD.BISHOP:
+ position.setBishop(color, square);
+ break;
+ case TCD.ROOK:
+ position.setRook(color, square);
+ break;
+ case TCD.QUEEN:
+ position.setQueen(color, square);
+ break;
+ case TCD.KING:
+ position.setKing(color, square);
+ break;
+ default:
+ throw new ParseException("parse.tcd.incorrect.piece");
+ }
+ }
+ piece = iterator.next();
+ }
+ }
+
+ private void _parseAddition(Position position, TCDIterator iterator) throws ParseException {
+ if (iterator.hasNext()) {
+ byte frame = iterator.next();
+ if (iterator.isLast() && frame != TCD.END) {
+ throw new ParseException("parse.tcd.incorrect.end");
+ } else {
+ boolean isEndPosition = false;
+ while (!isEndPosition) {
+ switch (frame) {
+ case TCD.MOVE:
+ position.setMove(
+ _parseMove(iterator)
+ );
+ break;
+ case TCD.CASTLE_WHITE:
+ position.setCastle(
+ Color.WHITE, _parseCastle(iterator)
+ );
+ break;
+ case TCD.CASTLE_BLACK:
+ position.setCastle(
+ Color.BLACK, _parseCastle(iterator)
+ );
+ break;
+ case TCD.EN_PASSANT:
+ position.setEnPassant(
+ _parseSquare(iterator)
+ );
+ break;
+ case TCD.HALFMOVE:
+ position.setHalfMove(
+ _parseNumber(iterator)
+ );
+ break;
+ case TCD.FULLMOVE:
+ position.setFullMove(
+ _parseNumber(iterator)
+ );
+ break;
+ default:
+ throw new ParseException("parse.tcd.incorrect.addition");
+ }
+ isEndPosition = true;
+ if (iterator.hasNext()) {
+ frame = iterator.next();
+ if (iterator.isLast() && frame != TCD.END) {
+ throw new ParseException("parse.tcd.incorrect.end");
+ }
+ isEndPosition = iterator.isLast();
+ }
+ }
+ }
+ }
+ }
+
+ private Square _parseSquare(TCDIterator iterator) throws ParseException {
+ byte vl = iterator.next();
+ byte hl = iterator.next();
+ return Square.getSquare(vl, hl);
+ }
+
+ private Color _parseMove(TCDIterator iterator) throws ParseException {
+ byte frame = iterator.next();
+ if (TCD.isNotColor(frame))
+ throw new ParseException("parse.tcd.incorrect.move.color");
+ return frame == TCD.WHITE ? Color.WHITE : Color.BLACK;
+ }
+
+ private Castle _parseCastle(TCDIterator iterator) throws ParseException {
+ byte frame = iterator.next();
+ if (TCD.isNotCastle(frame))
+ throw new ParseException("parse.tcd.incorrect.castle");
+ Castle castle = Castle.NONE;
+ switch (frame) {
+ case TCD.CASTLE_KING:
+ castle = Castle.KING;
+ break;
+ case TCD.CASTLE_QUEEN:
+ castle = Castle.QUEEN;
+ break;
+ case TCD.CASTLE_BOTH:
+ castle = Castle.BOTH;
+ break;
+ }
+ return castle;
+ }
+
+ private int _parseNumber(TCDIterator iterator) throws ParseException {
+ return iterator.next() << (2 * TCD.FRAME_LENGTH)
+ | iterator.next() << TCD.FRAME_LENGTH
+ | iterator.next();
+ }
+
+ public static Parser getInstance() {
+ return _instance;
+ }
+
+
+ public static void main(String[] args) throws ParseException {
+ //Position position = getInstance().parse("A7ONMILHJJIFCJEDO0ECFD0OvFV+4fnNQwOYoWaG-h5pgG");
+ //Position position = getInstance().parse("xG");
+ Position position = getInstance().parse("A7ONMILHJJIFCJEDO0ECFDGOvFV+4fnNQwOYoWaG-h5pgG");
+ System.out.println(position);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.tcg;
+
+import org.hedgecode.chess.tcd.TCD;
+
+/**
+ * Tiny Chess Game (TCG) constants.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class TCG {
+
+ public static final byte PAWN = TCD.PAWN;
+ public static final byte KNIGHT = TCD.KNIGHT;
+ public static final byte BISHOP = TCD.BISHOP;
+ public static final byte ROOK = TCD.ROOK;
+ public static final byte QUEEN = TCD.QUEEN;
+ public static final byte KING = TCD.KING;
+
+ public static final byte[][] SQUARE = TCD.SQUARE;
+
+ private TCG() {
+ }
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.tcg;
+
+/**
+ * Tiny Chess Game (TCG) builder.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class TCGBuilder {
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.tcg;
+
+/**
+ * Tiny Chess Game (TCG) parser.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class TCGParser {
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+import java.util.List;
+
+/**
+ * Universal Chess Interface (UCI) Acceptor.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Acceptor {
+
+ void start();
+
+ void id(String params);
+
+ void uciOK(String params);
+
+ void readyOK(String params);
+
+ void setOption(String name);
+ void setOption(String name, boolean def);
+ void setOption(String name, int def, int min, int max);
+ void setOption(String name, String def);
+ void setOption(String name, String def, List<String> vars);
+
+ void terminate(String params);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+import java.util.ResourceBundle;
+
+/**
+ * UCI Acceptor Exception.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class AcceptorException extends Exception {
+
+ private static final String ACCEPTOR = "UCI Acceptor: ";
+
+ private static final ResourceBundle LOCALE_BUNDLE =
+ ResourceBundle.getBundle(UCIConstants.LOCALE_BUNDLE_FILE);
+
+ private String localeKey;
+ private String message;
+
+ public AcceptorException(String localeKey) {
+ this.localeKey = localeKey;
+ this.message = null;
+ }
+
+ public AcceptorException(String localeKey, String message) {
+ this.localeKey = localeKey;
+ this.message = message;
+ }
+
+ public String getLocaleKey() {
+ return localeKey;
+ }
+
+ public String getMessage() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(ACCEPTOR);
+ sb.append(
+ LOCALE_BUNDLE.getString(localeKey)
+ );
+ if (message != null)
+ sb.append(": [").append(message).append("]");
+ return message;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+/**
+ * Universal Chess Interface (UCI) Acceptor Runner.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface AcceptorRunner extends Runner<Acceptor, AcceptorException> {
+
+ @Override
+ Acceptor init() throws AcceptorException;
+
+ @Override
+ void run(CommandExecutor commandExecutor) throws AcceptorException;
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+import java.util.List;
+
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.OptionParams;
+import org.hedgecode.chess.uci.command.OptionType;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class AcceptorStub implements Acceptor {
+
+ private static final String LOG_TO_FORMAT = ">> %s %s";
+ private static final String LOG_FROM_FORMAT = "<< %s %s";
+
+ private CommandExecutor commandExecutor;
+
+ AcceptorStub() {
+ }
+
+ public void init(CommandExecutor executor) {
+ commandExecutor = executor;
+ }
+
+ @Override
+ public void start() {
+ commandExecutor.exec(
+ UCIConstants.UCI, CommandDirection.TO_ENGINE, null
+ );
+ log(CommandDirection.TO_ENGINE, UCIConstants.UCI, null);
+ }
+
+ @Override
+ public void id(String params) {
+ log(CommandDirection.FROM_ENGINE, UCIConstants.ID, params);
+ }
+
+ @Override
+ public void uciOK(String params) {
+ log(CommandDirection.FROM_ENGINE, UCIConstants.UCI_OK, params);
+ commandExecutor.exec(
+ UCIConstants.IS_READY, CommandDirection.TO_ENGINE, null
+ );
+ log(CommandDirection.TO_ENGINE, UCIConstants.IS_READY, null);
+ }
+
+ @Override
+ public void readyOK(String params) {
+ log(CommandDirection.FROM_ENGINE, UCIConstants.READY_OK, params);
+ commandExecutor.exec(
+ UCIConstants.QUIT, CommandDirection.TO_ENGINE, null
+ );
+ log(CommandDirection.TO_ENGINE, UCIConstants.QUIT, null);
+ }
+
+ @Override
+ public void setOption(String name) {
+ log(
+ CommandDirection.FROM_ENGINE,
+ UCIConstants.OPTION,
+ String.format(
+ "%s %s %s %s",
+ OptionParams.OPTION_NAME, name, OptionParams.OPTION_TYPE, OptionType.BUTTON.type()
+ )
+ );
+ }
+
+ @Override
+ public void setOption(String name, boolean def) {
+ log(
+ CommandDirection.FROM_ENGINE,
+ UCIConstants.OPTION,
+ String.format(
+ "%s %s %s %s %s %b",
+ OptionParams.OPTION_NAME, name, OptionParams.OPTION_TYPE, OptionType.CHECK.type(),
+ OptionParams.OPTION_DEFAULT, def
+ )
+ );
+ }
+
+ @Override
+ public void setOption(String name, int def, int min, int max) {
+ log(
+ CommandDirection.FROM_ENGINE,
+ UCIConstants.OPTION,
+ String.format(
+ "%s %s %s %s %s %d %s %d %s %d",
+ OptionParams.OPTION_NAME, name, OptionParams.OPTION_TYPE, OptionType.SPIN.type(),
+ OptionParams.OPTION_DEFAULT, def, OptionParams.OPTION_MIN, min, OptionParams.OPTION_MAX, max
+ )
+ );
+ }
+
+ @Override
+ public void setOption(String name, String def) {
+ log(
+ CommandDirection.FROM_ENGINE,
+ UCIConstants.OPTION,
+ String.format(
+ "%s %s %s %s %s %s",
+ OptionParams.OPTION_NAME, name, OptionParams.OPTION_TYPE, OptionType.STRING.type(),
+ OptionParams.OPTION_DEFAULT, def == null ? "" : def
+ )
+ );
+ }
+
+ @Override
+ public void setOption(String name, String def, List<String> vars) {
+ StringBuilder varOptions = new StringBuilder();
+ for (String var : vars)
+ varOptions.append(
+ String.format("%s %s ", OptionParams.OPTION_VAR, var == null ? "" : var)
+ );
+ log(
+ CommandDirection.FROM_ENGINE,
+ UCIConstants.OPTION,
+ String.format(
+ "%s %s %s %s %s %s %s",
+ OptionParams.OPTION_NAME, name, OptionParams.OPTION_TYPE, OptionType.COMBO.type(),
+ OptionParams.OPTION_DEFAULT, def == null ? "" : def, varOptions.toString().trim()
+ )
+ );
+ }
+
+ @Override
+ public void terminate(String params) {
+ log(CommandDirection.FROM_ENGINE, UCIConstants.TERMINATE, params);
+ }
+
+ private void log(CommandDirection direction, String name, String params) {
+ System.out.println(
+ String.format(
+ CommandDirection.TO_ENGINE.equals(direction)
+ ? LOG_TO_FORMAT
+ : LOG_FROM_FORMAT,
+ name,
+ params != null ? params : ""
+ ).trim()
+ );
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class AcceptorStubRunner implements AcceptorRunner {
+
+ private AcceptorStub acceptor;
+
+ AcceptorStubRunner() {
+ acceptor = new AcceptorStub();
+ }
+
+ @Override
+ public Acceptor init() throws AcceptorException {
+ return acceptor;
+ }
+
+ @Override
+ public void run(final CommandExecutor commandExecutor) throws AcceptorException {
+ acceptor.init(commandExecutor);
+ acceptor.start();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class CommandDescriptor {
+
+ private static final char PKG_SEPARATOR = '.';
+ private static final char DIR_SEPARATOR = '/';
+ private static final String CLASS_FILE_SUFFIX = ".class";
+
+ private static final String PACKAGE_IS_NOT_EXISTS = "The package '%s' is not exists.";
+
+ private Map<String, UCICommand> commandsTo = new HashMap<>();
+ private Map<String, UCICommand> commandsFrom = new HashMap<>();
+
+ CommandDescriptor() throws Exception {
+ initCommands();
+ }
+
+ private void initCommands() throws Exception {
+ initCommands(
+ CommandDescriptor.class.getPackage().getName()
+ );
+ }
+
+ private void initCommands(String packageName) throws Exception {
+ URL packageUrl = Thread.currentThread().getContextClassLoader().getResource(
+ packageName.replace(PKG_SEPARATOR, DIR_SEPARATOR)
+ );
+ if (packageUrl == null)
+ throw new IllegalArgumentException(
+ String.format(PACKAGE_IS_NOT_EXISTS, packageName)
+ );
+
+ List<Class> commandClasses = findCommands(
+ new File(
+ packageUrl.getFile()
+ ),
+ packageName
+ );
+
+ commandsTo.clear();
+ commandsFrom.clear();
+ for (Class commandClass : commandClasses) {
+ if (UCICommand.class.isAssignableFrom(commandClass)) {
+ UCICommand uciCommand = (UCICommand) commandClass.newInstance();
+ Command command = (Command) commandClass.getAnnotation(Command.class);
+ switch (command.direction()) {
+ case TO_ENGINE:
+ commandsTo.put(
+ command.name(), uciCommand
+ );
+ break;
+ case FROM_ENGINE:
+ commandsFrom.put(
+ command.name(), uciCommand
+ );
+ break;
+ }
+ }
+ }
+ }
+
+ private List<Class> findCommands(File dir, String packageName) throws Exception {
+ List<Class> commands = new ArrayList<>();
+
+ File[] classFiles = dir.listFiles(
+ new FilenameFilter() {
+ public boolean accept(File file, String name) {
+ return name.endsWith(CLASS_FILE_SUFFIX);
+ }
+ }
+ );
+ if (classFiles != null) {
+ for (File classFile : classFiles) {
+ String className = packageName + PKG_SEPARATOR + classFile.getName();
+ int endIndex = className.length() - CLASS_FILE_SUFFIX.length();
+ className = className.substring(0, endIndex);
+ Class clazz = Class.forName(className);
+ if (clazz.isAnnotationPresent(Command.class)) {
+ commands.add(clazz);
+ }
+ }
+ }
+
+ File[] subDirs = dir.listFiles(
+ new FilenameFilter() {
+ public boolean accept(File file, String name) {
+ return file.isDirectory();
+ }
+ }
+ );
+ if (subDirs != null) {
+ for (File subDir : subDirs) {
+ commands.addAll(
+ findCommands(
+ subDir,
+ packageName + PKG_SEPARATOR + subDir.getName()
+ )
+ );
+ }
+ }
+
+ return commands;
+ }
+
+ public UCICommand getCommand(String name, CommandDirection direction) {
+ switch (direction) {
+ case TO_ENGINE:
+ return commandsTo.get(name);
+ case FROM_ENGINE:
+ return commandsFrom.get(name);
+ }
+ return null;
+ }
+
+
+ public static void main(String[] arg) throws Exception {
+ CommandDescriptor cd = new CommandDescriptor();
+ //cd.initCommands();
+ UCICommand command;
+ command = cd.getCommand("uci", CommandDirection.TO_ENGINE);
+ System.out.println(command);
+ command = cd.getCommand("debug", CommandDirection.TO_ENGINE);
+ System.out.println(command);
+ command = cd.getCommand("test", CommandDirection.TO_ENGINE);
+ System.out.println(command);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+import java.io.File;
+import java.nio.file.Paths;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class CommandEnvironment {
+
+ private static final String ENGINE_BIN_DIR = Paths.get("bin").toAbsolutePath().toString();
+
+
+ public static void main(String... args) throws Exception {
+
+ EngineRunner engineRunner = new ExternalEngineRunner(
+ ENGINE_BIN_DIR + File.separator + "stockfish.exe" // "houdini.exe" "komodo.exe"
+ );
+ Engine engine = engineRunner.init();
+
+ AcceptorRunner acceptorRunner = new ConsoleAcceptorRunner(); // new AcceptorStubRunner();
+ Acceptor acceptor = acceptorRunner.init();
+ //AcceptorStub acceptor = new AcceptorStub();
+
+ CommandExecutor commandExecutor = SyncCommandExecutor.Factory.create(engine, acceptor);
+
+ //acceptor.init(commandExecutor);
+ engineRunner.run(commandExecutor);
+ acceptorRunner.run(commandExecutor);
+ //acceptor.start();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class CommandException extends Exception {
+
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+
+/**
+ * UCI Command Executor.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface CommandExecutor {
+
+ void exec(String commandName, CommandDirection direction, String params);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.List;
+import java.util.Scanner;
+
+import org.hedgecode.chess.uci.command.OptionParams;
+import org.hedgecode.chess.uci.command.OptionType;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class ConsoleAcceptor implements Acceptor {
+
+ private class ConsoleReceiver implements Receiver<String> {
+
+ private Scanner scanner;
+ private boolean isActive;
+
+ ConsoleReceiver(InputStream input) {
+ scanner = new Scanner(input);
+ isActive = true;
+ }
+
+ @Override
+ public boolean isActive() {
+ return isActive;
+ }
+
+ @Override
+ public boolean hasCommand() {
+ return isActive && scanner.hasNextLine();
+ }
+
+ @Override
+ public String receiveCommand() {
+ return scanner.nextLine();
+ }
+
+ @Override
+ public void stop() {
+ isActive = false;
+ }
+
+ @Override
+ public void close() {
+ scanner.close();
+ }
+ }
+
+ private ConsoleReceiver receiver;
+ private PrintWriter writer;
+
+ ConsoleAcceptor(InputStream input, OutputStream output) {
+ receiver = new ConsoleReceiver(input);
+ writer = new PrintWriter(output, true);
+ }
+
+ public Receiver<String> receiver() {
+ return receiver;
+ }
+
+ @Override
+ public void start() {
+ }
+
+ @Override
+ public void id(String params) {
+ console(UCIConstants.ID, params);
+ }
+
+ @Override
+ public void uciOK(String params) {
+ console(UCIConstants.UCI_OK, params);
+ }
+
+ @Override
+ public void readyOK(String params) {
+ console(UCIConstants.READY_OK, params);
+ }
+
+ @Override
+ public void setOption(String name) {
+ console(
+ UCIConstants.OPTION,
+ String.format(
+ "%s %s %s %s",
+ OptionParams.OPTION_NAME, name, OptionParams.OPTION_TYPE, OptionType.BUTTON.type()
+ )
+ );
+ }
+
+ @Override
+ public void setOption(String name, boolean def) {
+ console(
+ UCIConstants.OPTION,
+ String.format(
+ "%s %s %s %s %s %b",
+ OptionParams.OPTION_NAME, name, OptionParams.OPTION_TYPE, OptionType.CHECK.type(),
+ OptionParams.OPTION_DEFAULT, def
+ )
+ );
+ }
+
+ @Override
+ public void setOption(String name, int def, int min, int max) {
+ console(
+ UCIConstants.OPTION,
+ String.format(
+ "%s %s %s %s %s %d %s %d %s %d",
+ OptionParams.OPTION_NAME, name, OptionParams.OPTION_TYPE, OptionType.SPIN.type(),
+ OptionParams.OPTION_DEFAULT, def, OptionParams.OPTION_MIN, min, OptionParams.OPTION_MAX, max
+ )
+ );
+ }
+
+ @Override
+ public void setOption(String name, String def) {
+ console(
+ UCIConstants.OPTION,
+ String.format(
+ "%s %s %s %s %s %s",
+ OptionParams.OPTION_NAME, name, OptionParams.OPTION_TYPE, OptionType.STRING.type(),
+ OptionParams.OPTION_DEFAULT, def == null ? "" : def
+ )
+ );
+ }
+
+ @Override
+ public void setOption(String name, String def, List<String> vars) {
+ StringBuilder varOptions = new StringBuilder();
+ for (String var : vars)
+ varOptions.append(
+ String.format("%s %s ", OptionParams.OPTION_VAR, var == null ? "" : var)
+ );
+ console(
+ UCIConstants.OPTION,
+ String.format(
+ "%s %s %s %s %s %s %s",
+ OptionParams.OPTION_NAME, name, OptionParams.OPTION_TYPE, OptionType.COMBO.type(),
+ OptionParams.OPTION_DEFAULT, def == null ? "" : def, varOptions.toString().trim()
+ )
+ );
+ }
+
+ @Override
+ public void terminate(String params) {
+ receiver.stop();
+ }
+
+ private void console(String name, String params) {
+ writer.println(
+ String.format(
+ "%s %s",
+ name,
+ params != null ? params : ""
+ ).trim()
+ );
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.CommandParams;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class ConsoleAcceptorRunner implements AcceptorRunner {
+
+ private ConsoleAcceptor acceptor;
+
+ private boolean isRunning;
+
+ ConsoleAcceptorRunner() {
+ acceptor = new ConsoleAcceptor(
+ System.in, System.out
+ );
+ isRunning = false;
+ }
+
+ ConsoleAcceptorRunner(InputStream input, OutputStream output) {
+ acceptor = new ConsoleAcceptor(
+ input, output
+ );
+ isRunning = false;
+ }
+
+ @Override
+ public Acceptor init() throws AcceptorException {
+ if (isRunning)
+ throw new AcceptorException("uci.acceptor.already.run");
+ return acceptor;
+ }
+
+ public void run(final CommandExecutor commandExecutor) throws AcceptorException {
+ if (isRunning)
+ throw new AcceptorException("uci.acceptor.already.run");
+
+ Thread engineThread = new Thread(
+ new Runnable() {
+ public void run() {
+ Receiver<String> acceptorReceiver = acceptor.receiver();
+ try {
+ while (acceptorReceiver.isActive()) {
+ if (acceptorReceiver.hasCommand()) {
+ String command = acceptorReceiver.receiveCommand();
+ if (command.isEmpty()) continue;
+ CommandParams commandParams = new CommandParams(command);
+ commandExecutor.exec(
+ commandParams.getName(),
+ CommandDirection.TO_ENGINE,
+ commandParams.getParams()
+ );
+ if (UCIConstants.QUIT.equals(commandParams.getName()))
+ acceptorReceiver.stop();
+ }
+ }
+ } finally {
+ acceptorReceiver.close();
+ isRunning = false;
+ }
+ }
+ }
+ );
+ engineThread.start();
+ isRunning = true;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+/**
+ * Debug Mode for UCI Engine.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum DebugMode {
+
+ OFF,
+ ON;
+
+ public String value() {
+ return this.name().toLowerCase();
+ }
+
+ public static DebugMode get(String mode) {
+ for (DebugMode debugMode : DebugMode.values()) {
+ if (debugMode.name().equalsIgnoreCase(mode))
+ return debugMode;
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+/**
+ * Universal Chess Interface (UCI) Engine.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Engine {
+
+ void init();
+
+ void debug(DebugMode mode);
+
+ void isReady();
+
+ void go();
+
+ void stop();
+
+ void ponderhit();
+
+ void quit();
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+import java.util.ResourceBundle;
+
+/**
+ * UCI Engine Exception.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class EngineException extends Exception {
+
+ private static final String ENGINE = "UCI Engine: ";
+
+ private static final ResourceBundle LOCALE_BUNDLE =
+ ResourceBundle.getBundle(UCIConstants.LOCALE_BUNDLE_FILE);
+
+ private String localeKey;
+ private String message;
+
+ public EngineException(String localeKey) {
+ this.localeKey = localeKey;
+ this.message = null;
+ }
+
+ public EngineException(String localeKey, String message) {
+ this.localeKey = localeKey;
+ this.message = message;
+ }
+
+ public String getLocaleKey() {
+ return localeKey;
+ }
+
+ public String getMessage() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(ENGINE);
+ sb.append(
+ LOCALE_BUNDLE.getString(localeKey)
+ );
+ if (message != null)
+ sb.append(": [").append(message).append("]");
+ return message;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+/**
+ * Universal Chess Interface (UCI) Engine Runner.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface EngineRunner extends Runner<Engine, EngineException> {
+
+ @Override
+ Engine init() throws EngineException;
+
+ @Override
+ void run(CommandExecutor commandExecutor) throws EngineException;
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+
+/**
+ * External UCI Engine.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class ExternalEngine implements Engine {
+
+ private static final String COMMAND_FORMAT = "%s %s";
+ private static final String CRLF = System.getProperty("line.separator");
+
+ private BufferedWriter engineWriter;
+
+ ExternalEngine(BufferedWriter writer) {
+ engineWriter = writer;
+ }
+
+ private void write(String command) {
+ try {
+ engineWriter.write(command);
+ engineWriter.write(CRLF);
+ engineWriter.flush();
+ } catch (IOException ignored) {
+ }
+ }
+
+ private String format(String name, String params) {
+ return String.format(
+ COMMAND_FORMAT, name, params
+ );
+ }
+
+ @Override
+ public void init() {
+ write(
+ UCIConstants.UCI
+ );
+ }
+
+ @Override
+ public void debug(DebugMode mode) {
+ write(
+ format(
+ UCIConstants.DEBUG, mode.value()
+ )
+ );
+ }
+
+ @Override
+ public void isReady() {
+ write(
+ UCIConstants.IS_READY
+ );
+ }
+
+ @Override
+ public void go() {
+ write(
+ UCIConstants.GO // todo: + params
+ );
+ }
+
+ @Override
+ public void stop() {
+ write(
+ UCIConstants.STOP
+ );
+ }
+
+ @Override
+ public void ponderhit() {
+ write(
+ UCIConstants.PONDER_HIT
+ );
+ }
+
+ @Override
+ public void quit() {
+ write(
+ UCIConstants.QUIT
+ );
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.util.List;
+import java.util.Scanner;
+
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.CommandParams;
+
+/**
+ * External UCI Engine Runner.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class ExternalEngineRunner implements EngineRunner {
+
+ private Process process;
+ private ProcessBuilder processBuilder;
+
+ private BufferedReader reader;
+ private BufferedWriter writer;
+
+ private boolean isInit = false;
+
+ ExternalEngineRunner(String extEngineCommand) {
+ processBuilder = new ProcessBuilder(extEngineCommand);
+ }
+
+ ExternalEngineRunner(List<String> extEngineCommands) {
+ processBuilder = new ProcessBuilder(extEngineCommands);
+ }
+
+ @Override
+ public Engine init() throws EngineException {
+ if (isInit)
+ throw new EngineException("uci.engine.already.init");
+
+ try {
+ process = processBuilder.start();
+ } catch (IOException e) {
+ throw new EngineException("uci.engine.external.start", e.getLocalizedMessage());
+ }
+ reader = new BufferedReader(
+ new InputStreamReader(
+ process.getInputStream()
+ )
+ );
+ writer = new BufferedWriter(
+ new OutputStreamWriter(
+ process.getOutputStream()
+ )
+ );
+ isInit = true;
+
+ return new ExternalEngine(
+ writer
+ );
+ }
+
+ @Override
+ public void run(final CommandExecutor commandExecutor) throws EngineException {
+ if (!isInit)
+ throw new EngineException("uci.engine.not.init");
+
+ Thread engineThread = new Thread(
+ new Runnable() {
+ public void run() {
+ try {
+ Scanner scanner = new Scanner(reader);
+ while (scanner.hasNextLine()) {
+ String command = scanner.nextLine();
+ if (command.isEmpty()) continue;
+ CommandParams commandParams = new CommandParams(command);
+ commandExecutor.exec(
+ commandParams.getName(),
+ CommandDirection.FROM_ENGINE,
+ commandParams.getParams()
+ );
+ }
+ } finally {
+ try {
+ writer.close();
+ reader.close();
+ } catch (IOException ignored) {
+ }
+ commandExecutor.exec(
+ UCIConstants.TERMINATE,
+ CommandDirection.FROM_ENGINE,
+ null
+ );
+ }
+ }
+ }
+ );
+ engineThread.start();
+ }
+
+ public void run() throws IOException, InterruptedException {
+ //Map<String, String> environment = processBuilder.environment();
+ Process process = processBuilder.start();
+ InputStream is = process.getInputStream();
+ BufferedReader br = new BufferedReader(new InputStreamReader(is));
+ OutputStream os = process.getOutputStream();
+ BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
+
+ Thread engineThread = new Thread(
+ new Runnable() {
+ public void run() {
+ Scanner scanner = new Scanner(br); //
+ while (scanner.hasNextLine()) {
+ System.out.println(scanner.nextLine());
+ }
+/*
+ String line;
+ try {
+ while ((line = br.readLine()) != null) {
+ System.out.println(line);
+ bw.write("isready");
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+*/
+ System.out.println("Engine terminated.");
+ }
+ }
+ );
+ engineThread.start();
+
+ bw.write("uci\n");
+ bw.flush();
+ bw.write("isready\n");
+ bw.flush();
+ bw.write("quit\n");
+ bw.flush();
+
+ //process.waitFor();
+
+ }
+
+
+ public static void main(String... args) throws Exception {
+/*
+ String[] strings = " uci test one more test".trim().split("\\s+", 2);
+ for (String string : strings)
+ System.out.println(string);
+*/
+
+ new ExternalEngineRunner("stockfish.exe").run();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Receiver<T> {
+
+ boolean isActive();
+
+ boolean hasCommand();
+
+ T receiveCommand();
+
+ void stop();
+
+ void close();
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+/**
+ * Common Runner Interface based on commands.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Runner<T, E extends Exception> {
+
+ T init() throws E;
+
+ void run(CommandExecutor commandExecutor) throws E;
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+
+/**
+ * Synchronized UCI Command Executor.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class SyncCommandExecutor implements CommandExecutor {
+
+ private Engine engine;
+ private Acceptor acceptor;
+ private CommandDescriptor commandDescriptor;
+
+ private SyncCommandExecutor(Engine engine, Acceptor acceptor) throws Exception {
+ this.engine = engine;
+ this.acceptor = acceptor;
+ initDescriptor();
+ }
+
+ private void initDescriptor() throws Exception {
+ commandDescriptor = new CommandDescriptor();
+ }
+
+ @Override
+ public synchronized void exec(String commandName, CommandDirection direction, String params) {
+ UCICommand uciCommand = commandDescriptor.getCommand(
+ commandName, direction
+ );
+ if (uciCommand != null) {
+ uciCommand.exec(
+ engine, acceptor, params
+ );
+ } else {
+ System.out.println(
+ String.format("%s %s",
+ commandName,
+ params != null ? params : ""
+ ).trim()
+ ); // todo
+ }
+ }
+
+ static final class Factory {
+
+ static CommandExecutor create(Engine engine, Acceptor acceptor) throws Exception {
+ return new SyncCommandExecutor(engine, acceptor);
+ }
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Transmitter<T> {
+
+ boolean isActive();
+
+ boolean hasCommand();
+
+ T transmitCommand();
+
+ void addCommand(T command);
+
+ void stop();
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface UCICommand {
+
+ void exec(final Engine engine, final Acceptor acceptor, String params);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci;
+
+/**
+ * UCI protocol constants.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class UCIConstants {
+
+ public static final String UCI = "uci";
+ public static final String DEBUG = "debug";
+ public static final String IS_READY = "isready";
+ public static final String SET_OPTION = "setoption";
+ public static final String REGISTER = "register";
+ public static final String UCI_NEW_GAME = "ucinewgame";
+ public static final String POSITION = "position";
+ public static final String GO = "go";
+ public static final String STOP = "stop";
+ public static final String PONDER_HIT = "ponderhit";
+ public static final String QUIT = "quit";
+
+ public static final String ID = "id";
+ public static final String UCI_OK = "uciok";
+ public static final String READY_OK = "readyok";
+ public static final String BEST_MOVE = "bestmove";
+ public static final String COPY_PROTECTION = "copyprotection";
+ public static final String REGISTRATION = "registration";
+ public static final String INFO = "info";
+ public static final String OPTION = "option";
+ public static final String TERMINATE = "terminate";
+
+ public static final String COMMAND_SEP_REGEX = "\\s+";
+
+ public static final String NULLMOVE = "0000";
+ public static final String MOVE_REGEX = "^([a-h][1-8])([a-h][1-8])([nbrq])?$";
+ public static final int MOVE_REGEX_FROM = 1;
+ public static final int MOVE_REGEX_TO = 2;
+ public static final int MOVE_REGEX_PROMOTE = 3;
+
+ public static final String LOCALE_BUNDLE_FILE = "org.hedgecode.chess.uci.LocalStrings";
+
+
+ private UCIConstants() {
+ throw new AssertionError(
+ "No org.hedgecode.chess.uci.UCIConstants instances!"
+ );
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Target(value= ElementType.TYPE)
+@Retention(value= RetentionPolicy.RUNTIME)
+public @interface Command {
+
+ String name();
+
+ CommandDirection direction();
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.annotation;
+
+/**
+ * UCI command direction.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum CommandDirection {
+ /**
+ * Describes the commands sent from GUI to Engine.
+ */
+ TO_ENGINE,
+
+ /**
+ * Describes the commands sent from Engine to GUI.
+ */
+ FROM_ENGINE
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.hedgecode.chess.position.Piece;
+import org.hedgecode.chess.position.Square;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+
+/**
+ * Abstract UCI command with parsing functionality.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public abstract class AbstractCommand implements UCICommand {
+
+ private static final String NULLMOVE = UCIConstants.NULLMOVE;
+
+ private static final Pattern MOVE_PATTERN = Pattern.compile(UCIConstants.MOVE_REGEX);
+
+ private static final int SQUARE_FROM = UCIConstants.MOVE_REGEX_FROM;
+ private static final int SQUARE_TO = UCIConstants.MOVE_REGEX_TO;
+ private static final int PIECE_PROMOTE = UCIConstants.MOVE_REGEX_PROMOTE;
+
+
+ protected Move parseMove(String move) {
+ if (NULLMOVE.equals(move))
+ return new Move(null, null);
+
+ Matcher matcher = MOVE_PATTERN.matcher(move);
+ if (matcher.find()) {
+ return new Move(
+ Square.getSquare(matcher.group(SQUARE_FROM)),
+ Square.getSquare(matcher.group(SQUARE_TO)),
+ Piece.byLetter(matcher.group(PIECE_PROMOTE))
+ );
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command;
+
+import org.hedgecode.chess.uci.UCIConstants;
+
+/**
+ * Container class for UCI command with parameters.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class CommandParams {
+
+ private String name;
+ private String params;
+
+ public CommandParams(String command) {
+ String[] arrCommand = command.trim().split(
+ UCIConstants.COMMAND_SEP_REGEX, 2
+ );
+ name = arrCommand[0];
+ params = arrCommand.length > 1 ? arrCommand[1] : null;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getParams() {
+ return params;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command;
+
+/**
+ * Container class for values of UCI command "info".
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class InfoParams {
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command;
+
+import org.hedgecode.chess.game.AbstractMove;
+import org.hedgecode.chess.position.Piece;
+import org.hedgecode.chess.position.Square;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class Move extends AbstractMove {
+
+ private Piece promote;
+
+ protected Move(Square from, Square to) {
+ super(null, from, to);
+ this.promote = null;
+ }
+
+ protected Move(Square from, Square to, Piece promote) {
+ super(null, from, to);
+ this.promote = promote;
+ }
+
+ @Override
+ public boolean isCapture() {
+ return false;
+ }
+
+ @Override
+ public boolean isCastle() {
+ return false;
+ }
+
+ @Override
+ public boolean isPromote() {
+ return promote != null;
+ }
+
+ @Override
+ public Piece promote() {
+ return promote;
+ }
+
+ @Override
+ public boolean isCheck() {
+ return false;
+ }
+
+ @Override
+ public boolean isMate() {
+ return false;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Container class for values of UCI command "option".
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class OptionParams {
+
+ public static final String OPTION_NAME = "name";
+ public static final String OPTION_TYPE = "type";
+ public static final String OPTION_DEFAULT = "default";
+ public static final String OPTION_MIN = "min";
+ public static final String OPTION_MAX = "max";
+ public static final String OPTION_VAR = "var";
+
+ private static final String OPTION_PIPE = "|";
+ private static final String OPTION_EMPTY = "<empty>";
+
+ private static final Pattern OPTION_PATTERN =
+ Pattern.compile(
+ String.format("^\\s*%s(.*)%s\\s+(%s)(.*)$", OPTION_NAME, OPTION_TYPE, typeRegex())
+ );
+
+ private static final String PARAMS_REGEX = "%s\\s+([^\\s]+)\\s*";
+
+ private String name;
+ private OptionType type;
+
+ private String defValue;
+ private int minValue, maxValue;
+ private List<String> vars = new ArrayList<>();
+
+ private OptionParams(String name, String type, String params) {
+ this.name = name;
+ this.type = OptionType.get(type);
+ if (!params.isEmpty())
+ parseParams(params);
+ }
+
+ private void parseParams(String option) {
+ parseDefValue(option);
+ parseMinValue(option);
+ parseMaxValue(option);
+ parseVars(option);
+ }
+
+ private void parseDefValue(String option) {
+ Pattern pattern = Pattern.compile(
+ String.format(PARAMS_REGEX, OPTION_DEFAULT)
+ );
+ Matcher matcher = pattern.matcher(option);
+ if (matcher.find()) {
+ defValue = parseEmptyValue(matcher.group(1));
+ }
+ }
+
+ private void parseMinValue(String option) {
+ Pattern pattern = Pattern.compile(
+ String.format(PARAMS_REGEX, OPTION_MIN)
+ );
+ Matcher matcher = pattern.matcher(option);
+ if (matcher.find()) {
+ minValue = Integer.parseInt(
+ matcher.group(1)
+ );
+ }
+ }
+
+ private void parseMaxValue(String option) {
+ Pattern pattern = Pattern.compile(
+ String.format(PARAMS_REGEX, OPTION_MAX)
+ );
+ Matcher matcher = pattern.matcher(option);
+ if (matcher.find()) {
+ maxValue = Integer.parseInt(
+ matcher.group(1)
+ );
+ }
+ }
+
+ private void parseVars(String option) {
+ Pattern pattern = Pattern.compile(
+ String.format(PARAMS_REGEX, OPTION_VAR)
+ );
+ Matcher matcher = pattern.matcher(option);
+ vars.clear();
+ while (matcher.find()) {
+ vars.add(
+ parseEmptyValue(matcher.group(1))
+ );
+ }
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public OptionType getType() {
+ return type;
+ }
+
+ public String getDefValue() {
+ return defValue;
+ }
+
+ public int getMinValue() {
+ return minValue;
+ }
+
+ public int getMaxValue() {
+ return maxValue;
+ }
+
+ public List<String> getVars() {
+ return vars;
+ }
+
+ private String parseEmptyValue(String value) {
+ return OPTION_EMPTY.equals(value) ? "" : value;
+ }
+
+ private static String typeRegex() {
+ StringBuilder sb = new StringBuilder();
+ for (OptionType optionType : OptionType.values()) {
+ if (optionType.ordinal() > 0)
+ sb.append(OPTION_PIPE);
+ sb.append(optionType.type());
+ }
+ return sb.toString();
+ }
+
+ public static final class Factory {
+
+ public static OptionParams parse(String option) {
+ Matcher matcher = OPTION_PATTERN.matcher(option);
+ if (matcher.find()) {
+ return new OptionParams(
+ matcher.group(1).trim(),
+ matcher.group(2).trim(),
+ matcher.group(3).trim()
+ );
+ }
+ return null;
+ }
+
+ }
+
+
+ public static void main(String... args) throws Exception {
+ String[] strings = {"name Debug Log File type string default",
+ " name Contempt type spin default 21 min -100 max 100",
+ " name Analysis Contempt type combo default Both var Off var White var Black var Both",
+ "name Threads type spin default 1 min 1 max 512",
+ "name Hash type spin default 16 min 1 max 131072",
+ "name Clear Hash type button",
+ "name Ponder type check default false",
+ "name MultiPV type spin default 1 min 1 max 500",
+ "name Skill Level type spin default 20 min 0 max 20",
+ "name Move Overhead type spin default 30 min 0 max 5000",
+ "name Minimum Thinking Time type spin default 20 min 0 max 5000",
+ "name Slow Mover type spin default 84 min 10 max 1000",
+ "name nodestime type spin default 0 min 0 max 10000",
+ "name UCI_Chess960 type check default false",
+ "name UCI_AnalyseMode type check default false",
+ "name SyzygyPath type string default <empty>",
+ "name SyzygyProbeDepth type spin default 1 min 1 max 100",
+ "name Syzygy50MoveRule type check default true",
+ "name SyzygyProbeLimit type spin default 7 min 0 max 7"};
+
+ for (String string : strings) {
+ OptionParams optionParams = OptionParams.Factory.parse(string);
+ System.out.println(optionParams);
+ }
+ }
+
+
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command;
+
+/**
+ * Types of options that UCI Engine can send/receive.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum OptionType {
+
+ /**
+ * Checkbox that can either be true or false.
+ */
+ CHECK ("check"),
+
+ /**
+ * Spin wheel that can be an integer in a certain range.
+ */
+ SPIN ("spin"),
+
+ /**
+ * Combo box that can have different predefined strings as a value.
+ */
+ COMBO ("combo"),
+
+ /**
+ * Button that can be pressed to send a command to the engine.
+ */
+ BUTTON ("button"),
+
+ /**
+ * Text field that has a string as a value, an empty string has the value "<empty>".
+ */
+ STRING ("string");
+
+ private String type;
+
+ OptionType(String type) {
+ this.type = type;
+ }
+
+ public String type() {
+ return type;
+ }
+
+ public static OptionType get(String type) {
+ for (OptionType optionType : OptionType.values()) {
+ if (optionType.type().equals(type))
+ return optionType;
+ }
+ return null;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.from;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.BEST_MOVE,
+ direction = CommandDirection.FROM_ENGINE
+)
+public class BestMoveCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.from;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.COPY_PROTECTION,
+ direction = CommandDirection.FROM_ENGINE
+)
+public class CopyProtectionCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.from;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.ID,
+ direction = CommandDirection.FROM_ENGINE
+)
+public class IdCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+ acceptor.id(params);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.from;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.INFO,
+ direction = CommandDirection.FROM_ENGINE
+)
+public class InfoCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.from;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.UCI_OK,
+ direction = CommandDirection.FROM_ENGINE
+)
+public class OkCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+ acceptor.uciOK(params);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.from;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+import org.hedgecode.chess.uci.command.OptionParams;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.OPTION,
+ direction = CommandDirection.FROM_ENGINE
+)
+public class OptionCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+ OptionParams optionParams = OptionParams.Factory.parse(params);
+ if (optionParams != null) {
+ switch (optionParams.getType()) {
+ case CHECK:
+ acceptor.setOption(
+ optionParams.getName(),
+ Boolean.parseBoolean(optionParams.getDefValue())
+ );
+ break;
+ case SPIN:
+ acceptor.setOption(
+ optionParams.getName(),
+ Integer.parseInt(optionParams.getDefValue()),
+ optionParams.getMinValue(),
+ optionParams.getMaxValue()
+ );
+ break;
+ case COMBO:
+ acceptor.setOption(
+ optionParams.getName(),
+ optionParams.getDefValue(),
+ optionParams.getVars()
+ );
+ break;
+ case BUTTON:
+ acceptor.setOption(
+ optionParams.getName()
+ );
+ break;
+ case STRING:
+ acceptor.setOption(
+ optionParams.getName(),
+ optionParams.getDefValue()
+ );
+ break;
+ }
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.from;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.READY_OK,
+ direction = CommandDirection.FROM_ENGINE
+)
+public class ReadyOkCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+ acceptor.readyOK(params);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.from;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.REGISTRATION,
+ direction = CommandDirection.FROM_ENGINE
+)
+public class RegistrationCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.from;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.TERMINATE,
+ direction = CommandDirection.FROM_ENGINE
+)
+public class TerminateCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+ acceptor.terminate(params);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.to;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.DEBUG,
+ direction = CommandDirection.TO_ENGINE
+)
+public class DebugCommand extends AbstractCommand implements UCICommand {
+
+ private static final String PARAM_REGEX = "[((on)|(off))]";
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+ engine.debug(null); // todo
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.to;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.GO,
+ direction = CommandDirection.TO_ENGINE
+)
+public class GoCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.to;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.UCI,
+ direction = CommandDirection.TO_ENGINE
+)
+public class InitCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+ engine.init();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.to;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.IS_READY,
+ direction = CommandDirection.TO_ENGINE
+)
+public class IsReadyCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+ engine.isReady();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.to;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.UCI_NEW_GAME,
+ direction = CommandDirection.TO_ENGINE
+)
+public class NewGameCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.to;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.PONDER_HIT,
+ direction = CommandDirection.TO_ENGINE
+)
+public class PonderHitCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.to;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.POSITION,
+ direction = CommandDirection.TO_ENGINE
+)
+public class PositionCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.to;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.QUIT,
+ direction = CommandDirection.TO_ENGINE
+)
+public class QuitCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+ engine.quit();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.to;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.REGISTER,
+ direction = CommandDirection.TO_ENGINE
+)
+public class RegisterCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.to;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.SET_OPTION,
+ direction = CommandDirection.TO_ENGINE
+)
+public class SetOptionCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command.to;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+import org.hedgecode.chess.uci.UCICommand;
+import org.hedgecode.chess.uci.UCIConstants;
+import org.hedgecode.chess.uci.annotation.Command;
+import org.hedgecode.chess.uci.annotation.CommandDirection;
+import org.hedgecode.chess.uci.command.AbstractCommand;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Command(
+ name = UCIConstants.STOP,
+ direction = CommandDirection.TO_ENGINE
+)
+public class StopCommand extends AbstractCommand implements UCICommand {
+
+ @Override
+ public void exec(final Engine engine, final Acceptor acceptor, String params) {
+ engine.stop();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.wiki;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hedgecode.chess.position.Color;
+import org.hedgecode.chess.position.ColorPiece;
+import org.hedgecode.chess.position.Piece;
+
+/**
+ * Wikipedia chess diagram constants.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class Wiki {
+
+ public static final String CRLF = System.lineSeparator();
+
+ public static final String EMPTY = " ";
+ public static final String SEPARATOR = "|";
+
+ public static final String TEMPLATE_BEGIN = "{{";
+ public static final String TEMPLATE_END = "}}";
+
+ public static final String WHITE_PAWN = "pl";
+ public static final String WHITE_KNIGHT = "nl";
+ public static final String WHITE_BISHOP = "bl";
+ public static final String WHITE_ROOK = "rl";
+ public static final String WHITE_QUEEN = "ql";
+ public static final String WHITE_KING = "kl";
+
+ public static final String BLACK_PAWN = "pd";
+ public static final String BLACK_KNIGHT = "nd";
+ public static final String BLACK_BISHOP = "bd";
+ public static final String BLACK_ROOK = "rd";
+ public static final String BLACK_QUEEN = "qd";
+ public static final String BLACK_KING = "kd";
+
+ private static final Map<ColorPiece, String> PIECES = new HashMap<ColorPiece, String>() {
+ {
+ put(ColorPiece.WHITE_PAWN, WHITE_PAWN); put(ColorPiece.BLACK_PAWN, BLACK_PAWN);
+ put(ColorPiece.WHITE_KNIGHT, WHITE_KNIGHT); put(ColorPiece.BLACK_KNIGHT, BLACK_KNIGHT);
+ put(ColorPiece.WHITE_BISHOP, WHITE_BISHOP); put(ColorPiece.BLACK_BISHOP, BLACK_BISHOP);
+ put(ColorPiece.WHITE_ROOK, WHITE_ROOK); put(ColorPiece.BLACK_ROOK, BLACK_ROOK);
+ put(ColorPiece.WHITE_QUEEN, WHITE_QUEEN); put(ColorPiece.BLACK_QUEEN, BLACK_QUEEN);
+ put(ColorPiece.WHITE_KING, WHITE_KING); put(ColorPiece.BLACK_KING, BLACK_KING);
+ }
+ };
+
+ private static boolean withTemplate = false;
+
+ private Wiki() {
+ }
+
+ public static boolean withTemplate() {
+ return withTemplate;
+ }
+
+ public static void setTemplate(boolean isTemplate) {
+ withTemplate = isTemplate;
+ }
+
+ public static ColorPiece getColorPiece(String piece) {
+ if (piece != null && !EMPTY.equals(piece)) {
+ for (Map.Entry<ColorPiece, String> entry : PIECES.entrySet()) {
+ if (entry.getValue().equals(piece))
+ return entry.getKey();
+ }
+ }
+ return null;
+ }
+
+ public static String getWikiPiece(Color color, Piece piece) {
+ return getWikiPiece(
+ ColorPiece.getColorPiece(color, piece)
+ );
+ }
+
+ public static String getWikiPiece(ColorPiece colorPiece) {
+ return (colorPiece != null)
+ ? PIECES.get(colorPiece)
+ : EMPTY;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.wiki;
+
+import java.util.Map;
+import java.util.ResourceBundle;
+
+import org.hedgecode.chess.ChessHogConstants;
+import org.hedgecode.chess.position.Builder;
+import org.hedgecode.chess.position.Color;
+import org.hedgecode.chess.position.ColorPiece;
+import org.hedgecode.chess.position.Position;
+import org.hedgecode.chess.position.Positions;
+import org.hedgecode.chess.position.Square;
+
+/**
+ * Wikipedia chess diagram builder.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class WikiBuilder implements Builder {
+
+ private static Builder _instance = new WikiBuilder();
+
+ private WikiBuilder() {
+ }
+
+ @Override
+ public String build(Position position) {
+ return _build(
+ position, Wiki.withTemplate()
+ );
+ }
+
+ private String _build(Position position, boolean withTemplate) {
+ StringBuilder sb = new StringBuilder();
+ Map<Square, ColorPiece> squares = position.getSquares();
+
+ if (withTemplate) {
+ ResourceBundle resourceBundle =
+ ResourceBundle.getBundle(ChessHogConstants.LOCALE_BUNDLE_FILE);
+ sb.append(Wiki.TEMPLATE_BEGIN).append(
+ resourceBundle.getString("wiki.chess.diagram.name")
+ ).append(Wiki.CRLF);
+ sb.append(Wiki.SEPARATOR).append(Wiki.CRLF);
+ sb.append(Wiki.SEPARATOR).append(Wiki.CRLF);
+ }
+
+ for (int i = Square.getSize() - 1; i >= 0; --i) {
+ for (int j = 0; j < Square.getSize(); ++j) {
+ Square square = Square.getSquare(j, i);
+ ColorPiece piece = squares.get(square);
+ String pieceName = (piece != null) ? Wiki.getWikiPiece(piece) : Wiki.EMPTY;
+ sb.append(Wiki.SEPARATOR).append(pieceName);
+ }
+ sb.append(Wiki.CRLF);
+ }
+
+ if (withTemplate) {
+ sb.append(Wiki.SEPARATOR).append(Wiki.CRLF);
+ sb.append(Wiki.TEMPLATE_END).append(Wiki.CRLF);
+ }
+
+ return sb.toString();
+ }
+
+ public static Builder getInstance() {
+ return _instance;
+ }
+
+
+ public static void main(String[] args) {
+ // Position position = Positions.INITIAL.getPosition()
+ Position position = Positions.EMPTY.getPosition();
+ position.setKing(Color.WHITE, Square.A1);
+ position.setPawn(Color.WHITE, Square.A2);
+ position.setPawn(Color.WHITE, Square.E4);
+ position.setQueen(Color.WHITE, Square.A7);
+ position.setKing(Color.BLACK, Square.H8);
+ position.setPawn(Color.BLACK, Square.G7);
+ position.setPawn(Color.BLACK, Square.H7);
+ position.setKnight(Color.BLACK, Square.G2);
+ position.setBishop(Color.BLACK, Square.D4);
+ position.setRook(Color.BLACK, Square.E2);
+
+ Wiki.setTemplate(true);
+ System.out.println(
+ getInstance().build(position)
+ );
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.wiki;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.hedgecode.chess.position.ParseException;
+import org.hedgecode.chess.position.Parser;
+import org.hedgecode.chess.position.Position;
+import org.hedgecode.chess.position.Positions;
+import org.hedgecode.chess.position.Square;
+
+/**
+ * Wikipedia chess diagram parser.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class WikiParser implements Parser {
+
+ private static final String LINE_REGEX = "\\r?\\n";
+ private static final String SQUARE_REGEX = String.format("[%s]", Wiki.SEPARATOR);
+
+ private static final Pattern PATTERN =
+ Pattern.compile(
+ String.format("^([%s][^%s]*){%d}$", Wiki.SEPARATOR, Wiki.SEPARATOR, Square.getSize())
+ );
+
+ private static Parser _instance = new WikiParser();
+
+ private WikiParser() {
+ }
+
+ @Override
+ public Position parse(String string) throws ParseException {
+ return _parse(
+ string.split(LINE_REGEX)
+ );
+ }
+
+ private Position _parse(String[] strings) throws ParseException {
+ List<String> lines = new ArrayList<>();
+ for (String line : strings) {
+ Matcher matcher = PATTERN.matcher(line);
+ if (matcher.find()) {
+ lines.add(
+ matcher.group(0)
+ );
+ }
+ }
+ if (lines.size() != Square.getSize())
+ throw new ParseException("parse.wiki.incorrect.board");
+ Position position = Positions.EMPTY.getPosition();
+ _parsePieces(
+ lines.toArray(
+ new String[lines.size()]
+ ),
+ position
+ );
+ return position;
+ }
+
+ private void _parsePieces(String[] lines, Position position) throws ParseException {
+ for (int i = 0; i < lines.length; ++i) {
+ int line = lines.length - i;
+ String[] pieces = lines[i].split(SQUARE_REGEX, -1);
+ if (pieces.length != Square.getSize() + 1)
+ throw new ParseException("parse.wiki.incorrect.board");
+ for (int j = 1; j < pieces.length; ++j) {
+ position.setPiece(
+ Wiki.getColorPiece(pieces[j]),
+ Square.getSquare(j - 1, line - 1)
+ );
+ }
+ }
+ }
+
+ public static Parser getInstance() {
+ return _instance;
+ }
+
+
+ public static void main(String[] args) throws ParseException {
+ Position position = getInstance().parse(
+ "{{Шахматная диаграмма\n" +
+ "|\n" +
+ "|\n" +
+ "|rd|nd|bd|qd|kd|bd|nd|rd\n" +
+ "|pd|pd| |pd|pd|pd|pd|pd\n" +
+ "| | | | | | | |\n" +
+ "| | | | | | | |\n" +
+ "| | | |pd|pl| | |\r\n" +
+ "| | |pl| | | | |\n" +
+ "|pl|pl| | | |pl|pl|pl\n" +
+ "|rl|nl|bl|ql|kl|bl|nl|rl\n" +
+ "| }}"
+ );
+ System.out.println(position);
+ }
+
+}
--- /dev/null
+# Copyright (c) 2018. Developed by Hedgecode.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Default localized string information
+# Localized for Locale en_US
+
+parse.null.input.string=Null input string
+parse.ascii.incorrect.board=Incorrect board
+parse.fen.invalid.string=Invalid input
+parse.fen.incorrect.board=Incorrect board
+parse.tcd.index.out.of.bounds=Array Index Out Of Bounds
+parse.tcd.invalid.bytes=Invalid input bytes
+parse.tcd.incorrect.color=Incorrect color
+parse.tcd.incorrect.piece=Incorrect piece
+parse.tcd.incorrect.end=Incorrect end
+parse.tcd.incorrect.addition=Incorrect addition
+parse.tcd.incorrect.move.color=Incorrect move color
+parse.tcd.incorrect.castle=Incorrect castle
+parse.wiki.incorrect.board=Incorrect board
+wiki.chess.diagram.name=Chess diagram
--- /dev/null
+# Copyright (c) 2018. Developed by Hedgecode.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Localized for Locale ru_RU
+
+parse.null.input.string=
+parse.ascii.incorrect.board=
+parse.fen.invalid.string=
+parse.fen.incorrect.board=
+parse.tcd.index.out.of.bounds=
+parse.tcd.invalid.bytes=
+parse.tcd.incorrect.color=
+parse.tcd.incorrect.piece=
+parse.tcd.incorrect.end=
+parse.tcd.incorrect.addition=
+parse.tcd.incorrect.move.color=
+parse.tcd.incorrect.castle=
+parse.wiki.incorrect.board=
+wiki.chess.diagram.name=\u0428\u0430\u0445\u043C\u0430\u0442\u043D\u0430\u044F \u0434\u0438\u0430\u0433\u0440\u0430\u043C\u043C\u0430
--- /dev/null
+# Copyright (c) 2018. Developed by Hedgecode.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Default localized string information
+# Localized for Locale en_US
+
+uci.acceptor.already.run=UCI Acceptor already running
+uci.engine.not.init=UCI Engine not initialized
+uci.engine.already.init=UCI Engine already initialized
+uci.engine.already.run=UCI Engine already running
+uci.engine.external.start=Error occurred while starting external UCI engine
--- /dev/null
+# Copyright (c) 2018. Developed by Hedgecode.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Localized for Locale ru_RU
+
+uci.acceptor.already.run=UCI \u043F\u0440\u0438\u0451\u043C\u043D\u0438\u043A \u0443\u0436\u0435 \u0437\u0430\u043F\u0443\u0449\u0435\u043D
+uci.engine.not.init=UCI \u0434\u0432\u0438\u0436\u043E\u043A \u043D\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D
+uci.engine.already.init=UCI \u0434\u0432\u0438\u0436\u043E\u043A \u0443\u0436\u0435 \u0438\u043D\u0438\u0446\u0438\u0430\u043B\u0438\u0437\u0438\u0440\u043E\u0432\u0430\u043D
+uci.engine.already.run=UCI \u0434\u0432\u0438\u0436\u043E\u043A \u0443\u0436\u0435 \u0437\u0430\u043F\u0443\u0449\u0435\u043D
+uci.engine.external.start=\u041F\u0440\u0438 \u0437\u0430\u043F\u0443\u0441\u043A\u0435 \u0432\u043D\u0435\u0448\u043D\u0435\u0433\u043E UCI \u0434\u0432\u0438\u0436\u043A\u0430 \u0432\u043E\u0437\u043D\u0438\u043A\u043B\u0430 \u043E\u0448\u0438\u0431\u043A\u0430
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.configuration.XMLConfiguration;
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.SubnodeConfiguration;
+
+import org.junit.Test;
+
+import org.hedgecode.chess.fen.FENBuilderTest;
+import org.hedgecode.chess.position.Castle;
+import org.hedgecode.chess.position.Color;
+import org.hedgecode.chess.position.ColorPiece;
+import org.hedgecode.chess.position.Position;
+import org.hedgecode.chess.position.Positions;
+import org.hedgecode.chess.position.Square;
+
+/**
+ * Abstract Common Chess Position Test class.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public abstract class AbstractPositionTest extends AbstractXMLConfigTest {
+
+ protected static final String NAME = "name";
+ protected static final String POSITION = "position";
+
+ private static final String INITIAL = "initial";
+ private static final String EMPTY = "empty";
+ private static final String SQUARES = "squares";
+ private static final String MOVE = "move";
+ private static final String CASTLE = "castle";
+ private static final String EN_PASSANT = "enPassant";
+ private static final String HALFMOVE = "halfmove";
+ private static final String FULLMOVE = "fullmove";
+
+ private static final String MSG_POSITION = "[%s]:";
+ private static final String MSG_POSITION_SQUARE = "[%s -> Square %s]:";
+ private static final String MSG_POSITION_MOVE = "[%s -> Move]:";
+ private static final String MSG_POSITION_CASTLE = "[%s -> Castle (%s)]:";
+ private static final String MSG_POSITION_EN_PASSANT = "[%s -> En Passant]:";
+ private static final String MSG_POSITION_HALFMOVE = "[%s -> Halfmove]:";
+ private static final String MSG_POSITION_FULLMOVE = "[%s -> Fullmove]:";
+
+ private String positionName;
+
+ public abstract List<XMLConfiguration> getXMLPositions() throws Exception;
+
+ @Test
+ public void testPositions() throws Exception {
+ for (XMLConfiguration xmlConfig : getXMLPositions())
+ testPosition(xmlConfig);
+ }
+
+ public void testPosition(HierarchicalConfiguration xmlPosition) throws Exception {
+ boolean isInitial = false, isEmpty = false;
+ boolean isSquares = !xmlPosition.subset(SQUARES).isEmpty();
+ if (xmlPosition.containsKey(INITIAL))
+ isInitial = xmlPosition.getBoolean(INITIAL);
+ if (xmlPosition.containsKey(EMPTY))
+ isEmpty = xmlPosition.getBoolean(EMPTY);
+ assertTrue(
+ isInitial || isEmpty || isSquares
+ );
+ if (isSquares && !isEmpty) {
+ SubnodeConfiguration squaresNode = xmlPosition.configurationAt(SQUARES);
+ Iterator<String> keys = squaresNode.getKeys();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ String value = squaresNode.getString(key);
+ assertNotNull(
+ Square.getSquare(key)
+ );
+ assertNotNull(
+ ColorPiece.valueOf(value)
+ );
+ }
+ }
+ if (xmlPosition.containsKey(MOVE)) {
+ assertNotNull(
+ Color.valueOf(
+ xmlPosition.getString(MOVE)
+ )
+ );
+ }
+ if (!xmlPosition.subset(CASTLE).isEmpty()) {
+ SubnodeConfiguration castleNode = xmlPosition.configurationAt(CASTLE);
+ Iterator<String> keys = castleNode.getKeys();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ String value = castleNode.getString(key);
+ assertNotNull(
+ Color.valueOf(key.toUpperCase())
+ );
+ assertNotNull(
+ Castle.valueOf(value)
+ );
+ }
+ }
+ if (xmlPosition.containsKey(EN_PASSANT)) {
+ assertNotNull(
+ Square.getSquare(
+ xmlPosition.getString(EN_PASSANT)
+ )
+ );
+ }
+ if (xmlPosition.containsKey(HALFMOVE)) {
+ assertTrue(
+ xmlPosition.getInt(HALFMOVE, -1) >= 0
+ );
+ }
+ if (xmlPosition.containsKey(FULLMOVE)) {
+ assertTrue(
+ xmlPosition.getInt(FULLMOVE, 0) > 0
+ );
+ }
+ }
+
+ @Override
+ protected String getConfigName() {
+ return getClass().getSimpleName();
+ }
+
+ protected Position assignPosition(HierarchicalConfiguration xmlPosition) {
+ if (xmlPosition.containsKey(INITIAL) && xmlPosition.getBoolean(INITIAL)) {
+ return Positions.INITIAL.getPosition();
+ }
+ Position position = Positions.EMPTY.getPosition();
+ if (!xmlPosition.subset(SQUARES).isEmpty()) {
+ SubnodeConfiguration squaresNode = xmlPosition.configurationAt(SQUARES);
+ Iterator<String> keys = squaresNode.getKeys();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ String value = squaresNode.getString(key);
+ position.setPiece(
+ ColorPiece.valueOf(value),
+ Square.getSquare(key)
+ );
+ }
+ }
+ if (xmlPosition.containsKey(MOVE))
+ position.setMove(
+ Color.valueOf(
+ xmlPosition.getString(MOVE)
+ )
+ );
+ if (!xmlPosition.subset(CASTLE).isEmpty()) {
+ SubnodeConfiguration castleNode = xmlPosition.configurationAt(CASTLE);
+ Iterator<String> keys = castleNode.getKeys();
+ while (keys.hasNext()) {
+ String key = keys.next();
+ String value = castleNode.getString(key);
+ position.setCastle(
+ Color.valueOf(key.toUpperCase()),
+ Castle.valueOf(value)
+ );
+ }
+ }
+ if (xmlPosition.containsKey(EN_PASSANT))
+ position.setEnPassant(
+ Square.getSquare(
+ xmlPosition.getString(EN_PASSANT)
+ )
+ );
+ if (xmlPosition.containsKey(HALFMOVE))
+ position.setHalfMove(
+ xmlPosition.getInt(HALFMOVE)
+ );
+ if (xmlPosition.containsKey(FULLMOVE))
+ position.setFullMove(
+ xmlPosition.getInt(FULLMOVE)
+ );
+ return position;
+ }
+
+ protected void assertPositionEquals(Position expected, Position actual) {
+ assertDiagramEquals(
+ expected,
+ actual
+ );
+ assertEquals(
+ String.format(
+ MSG_POSITION_MOVE,
+ positionName
+ ),
+ expected.getMove(),
+ actual.getMove()
+ );
+ assertEquals(
+ String.format(
+ MSG_POSITION_CASTLE,
+ positionName,
+ Color.WHITE
+ ),
+ expected.getCastle(Color.WHITE),
+ actual.getCastle(Color.WHITE)
+ );
+ assertEquals(
+ String.format(
+ MSG_POSITION_CASTLE,
+ positionName,
+ Color.BLACK
+ ),
+ expected.getCastle(Color.BLACK),
+ actual.getCastle(Color.BLACK)
+ );
+ assertEquals(
+ String.format(
+ MSG_POSITION_EN_PASSANT,
+ positionName
+ ),
+ expected.getEnPassant(),
+ actual.getEnPassant()
+ );
+ assertEquals(
+ String.format(
+ MSG_POSITION_HALFMOVE,
+ positionName
+ ),
+ expected.getHalfMove(),
+ actual.getHalfMove()
+ );
+ assertEquals(
+ String.format(
+ MSG_POSITION_FULLMOVE,
+ positionName
+ ),
+ expected.getFullMove(),
+ actual.getFullMove()
+ );
+ }
+
+ protected void assertDiagramEquals(Position expected, Position actual) {
+ assertNotNull(
+ expected
+ );
+ assertNotNull(
+ actual
+ );
+ assertSquaresEquals(
+ expected.getSquares(),
+ actual.getSquares()
+ );
+ }
+
+ private void assertSquaresEquals(Map<Square, ColorPiece> expected, Map<Square, ColorPiece> actual) {
+ for (Map.Entry<Square, ColorPiece> entry : expected.entrySet()) {
+ assertEquals(
+ String.format(
+ MSG_POSITION_SQUARE,
+ positionName,
+ entry.getKey().name()
+ ),
+ entry.getValue(),
+ actual.get(entry.getKey())
+ );
+ }
+ }
+
+ protected void assertStringEquals(String expected, String actual) {
+ assertEquals(
+ String.format(
+ MSG_POSITION,
+ positionName
+ ),
+ expected,
+ actual
+ );
+ }
+
+ public String getPositionName() {
+ return positionName;
+ }
+
+ protected void setPositionName(String name) {
+ positionName = name;
+ }
+
+
+/*
+ public static void main(String[] args) throws Exception {
+ XMLConfiguration xmlConfig = new XMLConfiguration(
+ new File(
+ FENBuilderTest.class.getResource("FENBuilderTest.xml").toURI()
+ )
+ );
+ for (HierarchicalConfiguration testConfig : xmlConfig.configurationsAt(TESTS)) {
+ AbstractPositionTest.testPosition(
+ testConfig.configurationAt(POSITION)
+ );
+ }
+ }
+*/
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess;
+
+import java.io.File;
+
+import org.apache.commons.configuration.XMLConfiguration;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+/**
+ * Abstract Test class with input params from XML file.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public abstract class AbstractXMLConfigTest extends Assert {
+
+ private static final String RESOURCES_ROOT = "/";
+ private static final String XML_EXT = ".xml";
+
+ protected static final String CONFIG = "config";
+ protected static final String TESTS = "tests.test";
+
+ @Test
+ public void testXML() throws Exception {
+ XMLConfiguration xmlConfig = getXMLConfig();
+ assertTrue(
+ CONFIG.equals(xmlConfig.getRoot().getName())
+ );
+ assertTrue(
+ xmlConfig.configurationsAt(TESTS).size() > 0
+ );
+ }
+
+ protected abstract String getConfigName();
+
+ protected XMLConfiguration getXMLConfig() throws Exception {
+ String xmlConfigName = getConfigName() + XML_EXT;
+ return new XMLConfiguration(
+ getResourceFile(
+ xmlConfigName
+ )
+ );
+ }
+
+ protected XMLConfiguration getDefXMLConfig() throws Exception {
+ return new XMLConfiguration(
+ getResourceFile(
+ getClass().getSimpleName() + XML_EXT
+ )
+ );
+ }
+
+ private File getResourceFile(String name) throws Exception {
+ if (getClass().getResource(name) != null)
+ return new File(
+ getClass().getResource(name).toURI()
+ );
+ return new File(
+ getClass().getResource(RESOURCES_ROOT).getPath() + name
+ );
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.ascii;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import org.hedgecode.chess.AbstractPositionTest;
+import org.hedgecode.chess.position.Builder;
+import org.hedgecode.chess.position.Position;
+
+/**
+ * Tests for {@link ASCIIBuilder}.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@RunWith(JUnit4.class)
+public class ASCIIBuilderTest extends AbstractPositionTest implements ASCIIPositionTest {
+
+ private static final String LINE_REGEX = "\\r?\\n";
+
+ @Test
+ public void testBuild() throws Exception {
+ Builder asciiBuilder = ASCIIBuilder.getInstance();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ setPositionName(
+ String.format(
+ MSG_ASCII_POSITION, testConfig.getString(NAME)
+ )
+ );
+ String ascii = testConfig.getString(ASCII_TAG);
+ Position position = assignPosition(
+ testConfig.configurationAt(POSITION)
+ );
+ if (testConfig.containsKey(ASCII_TYPE)) {
+ ASCII.setType(
+ ASCIIBoardType.valueOf(
+ testConfig.getString(ASCII_TYPE)
+ )
+ );
+ }
+ boolean withNotation = false;
+ if (testConfig.containsKey(ASCII_NOTATION)) {
+ withNotation = testConfig.getBoolean(ASCII_NOTATION);
+ }
+ ASCII.setNotation(withNotation);
+ assertStringEquals(
+ ascii,
+ asciiBuilder.build(position)
+ );
+ }
+ }
+
+ @Override
+ protected void assertStringEquals(String expected, String actual) {
+ assertNotNull(expected);
+ assertNotNull(actual);
+ String[] expectedLines = expected.split(LINE_REGEX);
+ String[] actualLines = actual.split(LINE_REGEX);
+ assertEquals(
+ expectedLines.length,
+ actualLines.length
+ );
+ for (int i = 0; i < expectedLines.length; ++i) {
+ super.assertStringEquals(
+ expectedLines[i].trim(),
+ actualLines[i].trim()
+ );
+ }
+ }
+
+ @Override
+ public List<XMLConfiguration> getXMLPositions() throws Exception {
+ List<XMLConfiguration> xmlPositions = new LinkedList<>();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ xmlPositions.add(
+ new XMLConfiguration(
+ testConfig.configurationAt(POSITION)
+ )
+ );
+ }
+ return xmlPositions;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.ascii;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import org.hedgecode.chess.AbstractPositionTest;
+import org.hedgecode.chess.position.Parser;
+import org.hedgecode.chess.position.Position;
+
+/**
+ * Tests for {@link ASCIIParser}.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@RunWith(JUnit4.class)
+public class ASCIIParserTest extends AbstractPositionTest implements ASCIIPositionTest {
+
+ @Test
+ public void testParse() throws Exception {
+ Parser asciiParser = ASCIIParser.getInstance();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ setPositionName(
+ String.format(
+ MSG_ASCII_POSITION, testConfig.getString(NAME)
+ )
+ );
+ String ascii = testConfig.getString(ASCII_TAG);
+ Position position = assignPosition(
+ testConfig.configurationAt(POSITION)
+ );
+ assertDiagramEquals(
+ position,
+ asciiParser.parse(ascii)
+ );
+ }
+ }
+
+ @Override
+ public List<XMLConfiguration> getXMLPositions() throws Exception {
+ List<XMLConfiguration> xmlPositions = new LinkedList<>();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ xmlPositions.add(
+ new XMLConfiguration(
+ testConfig.configurationAt(POSITION)
+ )
+ );
+ }
+ return xmlPositions;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.ascii;
+
+import java.util.List;
+
+import org.apache.commons.configuration.XMLConfiguration;
+
+/**
+ * ASCII Position Test Common Interface.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface ASCIIPositionTest {
+
+ String ASCII_TAG = "ascii";
+ String ASCII_TYPE = "asciiType";
+ String ASCII_NOTATION = "withNotation";
+ String MSG_ASCII_POSITION = "ASCII: %s";
+
+ List<XMLConfiguration> getXMLPositions() throws Exception;
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.fen;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import org.hedgecode.chess.AbstractPositionTest;
+import org.hedgecode.chess.position.Builder;
+import org.hedgecode.chess.position.Position;
+
+/**
+ * Tests for {@link FENBuilder}.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@RunWith(JUnit4.class)
+public class FENBuilderTest extends AbstractPositionTest implements FENPositionTest {
+
+ @Test
+ public void testBuild() throws Exception {
+ Builder fenBuilder = FENBuilder.getInstance();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ setPositionName(
+ String.format(
+ MSG_FEN_POSITION, testConfig.getString(NAME)
+ )
+ );
+ String fen = testConfig.getString(FEN_TAG);
+ Position position = assignPosition(
+ testConfig.configurationAt(POSITION)
+ );
+ assertStringEquals(
+ fen,
+ fenBuilder.build(position)
+ );
+ }
+ }
+
+ @Override
+ public List<XMLConfiguration> getXMLPositions() throws Exception {
+ List<XMLConfiguration> xmlPositions = new LinkedList<>();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ xmlPositions.add(
+ new XMLConfiguration(
+ testConfig.configurationAt(POSITION)
+ )
+ );
+ }
+ return xmlPositions;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.fen;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import org.hedgecode.chess.AbstractPositionTest;
+import org.hedgecode.chess.position.Parser;
+import org.hedgecode.chess.position.Position;
+
+/**
+ * Tests for {@link FENParser}.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@RunWith(JUnit4.class)
+public class FENParserTest extends AbstractPositionTest implements FENPositionTest {
+
+ @Test
+ public void testParse() throws Exception {
+ Parser fenParser = FENParser.getInstance();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ setPositionName(
+ String.format(
+ MSG_FEN_POSITION, testConfig.getString(NAME)
+ )
+ );
+ String fen = testConfig.getString(FEN_TAG);
+ Position position = assignPosition(
+ testConfig.configurationAt(POSITION)
+ );
+ assertPositionEquals(
+ position,
+ fenParser.parse(fen)
+ );
+ }
+ }
+
+ @Override
+ public List<XMLConfiguration> getXMLPositions() throws Exception {
+ List<XMLConfiguration> xmlPositions = new LinkedList<>();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ xmlPositions.add(
+ new XMLConfiguration(
+ testConfig.configurationAt(POSITION)
+ )
+ );
+ }
+ return xmlPositions;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.fen;
+
+import java.util.List;
+
+import org.apache.commons.configuration.XMLConfiguration;
+
+/**
+ * FEN Position Test Common Interface.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface FENPositionTest {
+
+ String FEN_TAG = "fen";
+ String MSG_FEN_POSITION = "FEN: %s";
+
+ List<XMLConfiguration> getXMLPositions() throws Exception;
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.tcd;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import org.hedgecode.chess.AbstractPositionTest;
+import org.hedgecode.chess.position.Builder;
+import org.hedgecode.chess.position.Position;
+
+/**
+ * Tests for {@link TCDBuilder}.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@RunWith(JUnit4.class)
+public class TCDBuilderTest extends AbstractPositionTest implements TCDPositionTest {
+
+ @Test
+ public void testBuild() throws Exception {
+ Builder tcdBuilder = TCDBuilder.getInstance();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ setPositionName(
+ String.format(
+ MSG_TCD_POSITION, testConfig.getString(NAME)
+ )
+ );
+ String tcd = testConfig.getString(TCD_TAG);
+ Position position = assignPosition(
+ testConfig.configurationAt(POSITION)
+ );
+ assertStringEquals(
+ tcd,
+ tcdBuilder.build(position)
+ );
+ }
+ }
+
+ @Override
+ public List<XMLConfiguration> getXMLPositions() throws Exception {
+ List<XMLConfiguration> xmlPositions = new LinkedList<>();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ xmlPositions.add(
+ new XMLConfiguration(
+ testConfig.configurationAt(POSITION)
+ )
+ );
+ }
+ return xmlPositions;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.tcd;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import org.hedgecode.chess.AbstractPositionTest;
+import org.hedgecode.chess.position.Parser;
+import org.hedgecode.chess.position.Position;
+
+/**
+ * Tests for {@link TCDParser}.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@RunWith(JUnit4.class)
+public class TCDParserTest extends AbstractPositionTest implements TCDPositionTest {
+
+ @Test
+ public void testParse() throws Exception {
+ Parser tcdParser = TCDParser.getInstance();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ setPositionName(
+ String.format(
+ MSG_TCD_POSITION, testConfig.getString(NAME)
+ )
+ );
+ String tcd = testConfig.getString(TCD_TAG);
+ Position position = assignPosition(
+ testConfig.configurationAt(POSITION)
+ );
+ assertPositionEquals(
+ position,
+ tcdParser.parse(tcd)
+ );
+ }
+ }
+
+ @Override
+ public List<XMLConfiguration> getXMLPositions() throws Exception {
+ List<XMLConfiguration> xmlPositions = new LinkedList<>();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ xmlPositions.add(
+ new XMLConfiguration(
+ testConfig.configurationAt(POSITION)
+ )
+ );
+ }
+ return xmlPositions;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.tcd;
+
+import java.util.List;
+
+import org.apache.commons.configuration.XMLConfiguration;
+
+/**
+ * TCD Position Test Common Interface.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface TCDPositionTest {
+
+ String TCD_TAG = "tcd";
+ String TCD_DIAGRAM = "isDiagram";
+ String MSG_TCD_POSITION = "TCD: %s";
+
+ List<XMLConfiguration> getXMLPositions() throws Exception;
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.uci.command;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import org.hedgecode.chess.uci.Acceptor;
+import org.hedgecode.chess.uci.Engine;
+
+/**
+ * Tests for {@link AbstractCommand}.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@RunWith(JUnit4.class)
+public class AbstractCommandTest extends Assert {
+
+ @Test
+ public void testParseMove() throws Exception {
+
+ String[] correctMoves = {"e2e4", "e7e5", "e1g1", "e7e8q", "0000"};
+ for (String correctMove : correctMoves) {
+ Move move = new AbstractCommand() {
+ @Override
+ public void exec(Engine engine, Acceptor acceptor, String params) {
+ throw new RuntimeException("Don't supported in test class!");
+ }
+ }.parseMove(correctMove);
+
+ assertNotNull(move);
+ }
+
+ String[] incorrectMoves = {"00e2", "e0e5", "e1j1", "a1a9", "e7e8k"};
+ for (String incorrectMove : incorrectMoves) {
+ Move move = new AbstractCommand() {
+ @Override
+ public void exec(Engine engine, Acceptor acceptor, String params) {
+ throw new RuntimeException("Don't supported in test class!");
+ }
+ }.parseMove(incorrectMove);
+
+ assertNull(move);
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.wiki;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import org.hedgecode.chess.AbstractPositionTest;
+import org.hedgecode.chess.position.Builder;
+import org.hedgecode.chess.position.Position;
+
+/**
+ * Tests for {@link WikiBuilder}.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@RunWith(JUnit4.class)
+public class WikiBuilderTest extends AbstractPositionTest implements WikiPositionTest {
+
+ private static final String LINE_REGEX = "\\r?\\n";
+
+ @Test
+ public void testBuild() throws Exception {
+ Builder wikiBuilder = WikiBuilder.getInstance();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ setPositionName(
+ String.format(
+ MSG_WIKI_POSITION, testConfig.getString(NAME)
+ )
+ );
+ String wiki = testConfig.getString(WIKI_TAG);
+ Position position = assignPosition(
+ testConfig.configurationAt(POSITION)
+ );
+ boolean withTemplate = false;
+ if (testConfig.containsKey(WIKI_TEMPLATE)) {
+ withTemplate = testConfig.getBoolean(WIKI_TEMPLATE);
+ }
+ Wiki.setTemplate(withTemplate);
+ assertStringEquals(
+ wiki,
+ wikiBuilder.build(position)
+ );
+ }
+ }
+
+ @Override
+ protected void assertStringEquals(String expected, String actual) {
+ assertNotNull(expected);
+ assertNotNull(actual);
+ String[] expectedLines = expected.split(LINE_REGEX);
+ String[] actualLines = actual.split(LINE_REGEX);
+ assertEquals(
+ expectedLines.length,
+ actualLines.length
+ );
+ for (int i = 0; i < expectedLines.length; ++i) {
+ super.assertStringEquals(
+ expectedLines[i].trim(),
+ actualLines[i].trim()
+ );
+ }
+ }
+
+ @Override
+ public List<XMLConfiguration> getXMLPositions() throws Exception {
+ List<XMLConfiguration> xmlPositions = new LinkedList<>();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ xmlPositions.add(
+ new XMLConfiguration(
+ testConfig.configurationAt(POSITION)
+ )
+ );
+ }
+ return xmlPositions;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.wiki;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.commons.configuration.HierarchicalConfiguration;
+import org.apache.commons.configuration.XMLConfiguration;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import org.hedgecode.chess.AbstractPositionTest;
+import org.hedgecode.chess.position.Parser;
+import org.hedgecode.chess.position.Position;
+
+/**
+ * Tests for {@link WikiParser}.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@RunWith(JUnit4.class)
+public class WikiParserTest extends AbstractPositionTest implements WikiPositionTest {
+
+ @Test
+ public void testParse() throws Exception {
+ Parser wikiParser = WikiParser.getInstance();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ setPositionName(
+ String.format(
+ MSG_WIKI_POSITION, testConfig.getString(NAME)
+ )
+ );
+ String wiki = testConfig.getString(WIKI_TAG);
+ Position position = assignPosition(
+ testConfig.configurationAt(POSITION)
+ );
+ boolean withTemplate = false;
+ if (testConfig.containsKey(WIKI_TEMPLATE)) {
+ withTemplate = testConfig.getBoolean(WIKI_TEMPLATE);
+ }
+ Wiki.setTemplate(withTemplate);
+ assertDiagramEquals(
+ position,
+ wikiParser.parse(wiki)
+ );
+ }
+ }
+
+ @Override
+ public List<XMLConfiguration> getXMLPositions() throws Exception {
+ List<XMLConfiguration> xmlPositions = new LinkedList<>();
+ for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) {
+ xmlPositions.add(
+ new XMLConfiguration(
+ testConfig.configurationAt(POSITION)
+ )
+ );
+ }
+ return xmlPositions;
+ }
+
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2018. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.chess.wiki;
+
+import java.util.List;
+
+import org.apache.commons.configuration.XMLConfiguration;
+
+/**
+ * Wiki Position Test Common Interface.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface WikiPositionTest {
+
+ String WIKI_TAG = "wiki";
+ String WIKI_TEMPLATE = "withTemplate";
+ String MSG_WIKI_POSITION = "WIKI: %s";
+
+ List<XMLConfiguration> getXMLPositions() throws Exception;
+
+}
--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+ ~ Copyright (c) 2018. Developed by Hedgecode.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<config>
+ <tests>
+ <test>
+ <name>Initial Position</name>
+ <ascii>
+ <![CDATA[
+ +-------------------------------+
+ | r | n | b | q | k | b | n | r |
+ +-------------------------------+
+ | p | p | p | p | p | p | p | p |
+ +-------------------------------+
+ | | | | | | | | |
+ +-------------------------------+
+ | | | | | | | | |
+ +-------------------------------+
+ | | | | | | | | |
+ +-------------------------------+
+ | | | | | | | | |
+ +-------------------------------+
+ | P | P | P | P | P | P | P | P |
+ +-------------------------------+
+ | R | N | B | Q | K | B | N | R |
+ +-------------------------------+
+ ]]>
+ </ascii>
+ <asciiType>HYPHEN</asciiType>
+ <position>
+ <initial>true</initial>
+ </position>
+ </test>
+ <test>
+ <name>Initial Position</name>
+ <ascii>
+ <![CDATA[
+ ___ ___ ___ ___ ___ ___ ___ ___
+ |_r_|_n_|_b_|_q_|_k_|_b_|_n_|_r_|
+ |_p_|_p_|_p_|_p_|_p_|_p_|_p_|_p_|
+ |___|___|___|___|___|___|___|___|
+ |___|___|___|___|___|___|___|___|
+ |___|___|___|___|___|___|___|___|
+ |___|___|___|___|___|___|___|___|
+ |_P_|_P_|_P_|_P_|_P_|_P_|_P_|_P_|
+ |_R_|_N_|_B_|_Q_|_K_|_B_|_N_|_R_|
+ ]]>
+ </ascii>
+ <asciiType>TIGHT</asciiType>
+ <position>
+ <initial>true</initial>
+ </position>
+ </test>
+ <test>
+ <name>Initial Position</name>
+ <ascii>
+ <![CDATA[
+ a b c d e f g h
+ +------------------------+
+ 8 | r n b q k b n r | 8
+ 7 | p p p p p p p p | 7
+ 6 | . . . . . . . . | 6
+ 5 | . . . . . . . . | 5
+ 4 | . . . . . . . . | 4
+ 3 | . . . . . . . . | 3
+ 2 | P P P P P P P P | 2
+ 1 | R N B Q K B N R | 1
+ +------------------------+
+ a b c d e f g h
+ ]]>
+ </ascii>
+ <asciiType>DOT</asciiType>
+ <withNotation>true</withNotation>
+ <position>
+ <initial>true</initial>
+ </position>
+ </test>
+ <test>
+ <name>Initial Position</name>
+ <ascii>
+ <![CDATA[
+ ╔═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╗
+ ║ r │ n │ b │ q │ k │ b │ n │ r ║
+ ╟───┼───┼───┼───┼───┼───┼───┼───╢
+ ║ p │ p │ p │ p │ p │ p │ p │ p ║
+ ╟───┼───┼───┼───┼───┼───┼───┼───╢
+ ║ │ │ │ │ │ │ │ ║
+ ╟───┼───┼───┼───┼───┼───┼───┼───╢
+ ║ │ │ │ │ │ │ │ ║
+ ╟───┼───┼───┼───┼───┼───┼───┼───╢
+ ║ │ │ │ │ │ │ │ ║
+ ╟───┼───┼───┼───┼───┼───┼───┼───╢
+ ║ │ │ │ │ │ │ │ ║
+ ╟───┼───┼───┼───┼───┼───┼───┼───╢
+ ║ P │ P │ P │ P │ P │ P │ P │ P ║
+ ╟───┼───┼───┼───┼───┼───┼───┼───╢
+ ║ R │ N │ B │ Q │ K │ B │ N │ R ║
+ ╚═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╝
+ ]]>
+ </ascii>
+ <asciiType>CP866</asciiType>
+ <withNotation>false</withNotation>
+ <position>
+ <initial>true</initial>
+ </position>
+ </test>
+ <test>
+ <name>Reti's Etude</name>
+ <ascii>
+ <![CDATA[
+ +------------------------+
+ | . . . . . . . K |
+ | . . . . . . . . |
+ | k . P . . . . . |
+ | . . . . . . . p |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ +------------------------+
+ ]]>
+ </ascii>
+ <asciiType>DOT</asciiType>
+ <position>
+ <squares>
+ <h8>WHITE_KING</h8>
+ <c6>WHITE_PAWN</c6>
+ <a6>BLACK_KING</a6>
+ <h5>BLACK_PAWN</h5>
+ </squares>
+ <move>WHITE</move>
+ </position>
+ </test>
+ <test>
+ <name>Empty Position</name>
+ <ascii>
+ <![CDATA[
+ +------------------------+
+ | . . . . . . . . |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ +------------------------+
+ ]]>
+ </ascii>
+ <asciiType>DOT</asciiType>
+ <position>
+ <empty>true</empty>
+ <move>WHITE</move>
+ </position>
+ </test>
+ </tests>
+</config>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+ ~ Copyright (c) 2018. Developed by Hedgecode.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<config>
+ <tests>
+ <test>
+ <name>Initial Position</name>
+ <ascii>
+ <![CDATA[
++-------------------------------+
+| r | n | b | q | k | b | n | r |
++-------------------------------+
+| p | p | p | p | p | p | p | p |
++-------------------------------+
+| | | | | | | | |
++-------------------------------+
+| | | | | | | | |
++-------------------------------+
+| | | | | | | | |
++-------------------------------+
+| | | | | | | | |
++-------------------------------+
+| P | P | P | P | P | P | P | P |
++-------------------------------+
+| R | N | B | Q | K | B | N | R |
++-------------------------------+
+ ]]>
+ </ascii>
+ <asciiType>HYPHEN</asciiType>
+ <position>
+ <initial>true</initial>
+ </position>
+ </test>
+ <test>
+ <name>Initial Position</name>
+ <ascii>
+ <![CDATA[
+ ___ ___ ___ ___ ___ ___ ___ ___
+|_r_|_n_|_b_|_q_|_k_|_b_|_n_|_r_|
+|_p_|_p_|_p_|_p_|_p_|_p_|_p_|_p_|
+|___|___|___|___|___|___|___|___|
+|___|___|___|___|___|___|___|___|
+|___|___|___|___|___|___|___|___|
+|___|___|___|___|___|___|___|___|
+|_P_|_P_|_P_|_P_|_P_|_P_|_P_|_P_|
+|_R_|_N_|_B_|_Q_|_K_|_B_|_N_|_R_|
+ ]]>
+ </ascii>
+ <asciiType>TIGHT</asciiType>
+ <position>
+ <initial>true</initial>
+ </position>
+ </test>
+ <test>
+ <name>Initial Position</name>
+ <ascii>
+ <![CDATA[
+ a b c d e f g h
+ +------------------------+
+ 8 | r n b q k b n r | 8
+ 7 | p p p p p p p p | 7
+ 6 | . . . . . . . . | 6
+ 5 | . . . . . . . . | 5
+ 4 | . . . . . . . . | 4
+ 3 | . . . . . . . . | 3
+ 2 | P P P P P P P P | 2
+ 1 | R N B Q K B N R | 1
+ +------------------------+
+ a b c d e f g h
+ ]]>
+ </ascii>
+ <asciiType>DOT</asciiType>
+ <withNotation>true</withNotation>
+ <position>
+ <initial>true</initial>
+ </position>
+ </test>
+ <test>
+ <name>Initial Position</name>
+ <ascii>
+ <![CDATA[
+╔═══╤═══╤═══╤═══╤═══╤═══╤═══╤═══╗
+║ r │ n │ b │ q │ k │ b │ n │ r ║
+╟───┼───┼───┼───┼───┼───┼───┼───╢
+║ p │ p │ p │ p │ p │ p │ p │ p ║
+╟───┼───┼───┼───┼───┼───┼───┼───╢
+║ │ │ │ │ │ │ │ ║
+╟───┼───┼───┼───┼───┼───┼───┼───╢
+║ │ │ │ │ │ │ │ ║
+╟───┼───┼───┼───┼───┼───┼───┼───╢
+║ │ │ │ │ │ │ │ ║
+╟───┼───┼───┼───┼───┼───┼───┼───╢
+║ │ │ │ │ │ │ │ ║
+╟───┼───┼───┼───┼───┼───┼───┼───╢
+║ P │ P │ P │ P │ P │ P │ P │ P ║
+╟───┼───┼───┼───┼───┼───┼───┼───╢
+║ R │ N │ B │ Q │ K │ B │ N │ R ║
+╚═══╧═══╧═══╧═══╧═══╧═══╧═══╧═══╝
+ ]]>
+ </ascii>
+ <asciiType>CP866</asciiType>
+ <withNotation>false</withNotation>
+ <position>
+ <initial>true</initial>
+ </position>
+ </test>
+ <test>
+ <name>Dilaram's Mate</name>
+ <ascii>
+ <![CDATA[
++-------------------------------+
+| | r | | | | | k | |
++-------------------------------+
+| | | | | | | | |
++-------------------------------+
+| | | | | | P | P | |
++-------------------------------+
+| K | | n | | | | | |
++-------------------------------+
+| | | | | | | N | R |
++-------------------------------+
+| | | | | | | | B |
++-------------------------------+
+| | r | | | | | | |
++-------------------------------+
+| | | | | | | | R |
++-------------------------------+
+ ]]>
+ </ascii>
+ <asciiType>HYPHEN</asciiType>
+ <position>
+ <squares>
+ <a5>WHITE_KING</a5>
+ <h4>WHITE_ROOK</h4>
+ <h1>WHITE_ROOK</h1>
+ <h3>WHITE_BISHOP</h3>
+ <g4>WHITE_KNIGHT</g4>
+ <f6>WHITE_PAWN</f6>
+ <g6>WHITE_PAWN</g6>
+ <g8>BLACK_KING</g8>
+ <b8>BLACK_ROOK</b8>
+ <b2>BLACK_ROOK</b2>
+ <c5>BLACK_KNIGHT</c5>
+ </squares>
+ <move>WHITE</move>
+ </position>
+ </test>
+ <test>
+ <name>Empty Position</name>
+ <ascii>
+ <![CDATA[
+ +------------------------+
+ | . . . . . . . . |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ | . . . . . . . . |
+ +------------------------+
+ ]]>
+ </ascii>
+ <asciiType>DOT</asciiType>
+ <position>
+ <empty>true</empty>
+ <move>WHITE</move>
+ </position>
+ </test>
+ </tests>
+</config>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+ ~ Copyright (c) 2018. Developed by Hedgecode.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<config>
+ <tests>
+ <test>
+ <name>Initial Position</name>
+ <fen>rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1</fen>
+ <position>
+ <initial>true</initial>
+ </position>
+ </test>
+ <test>
+ <name>Morphy's Opera Game</name>
+ <fen>4kb1r/p2n1ppp/4q3/4p1B1/4P3/1Q6/PPP2PPP/2KR4 w k - 0 16</fen>
+ <position>
+ <squares>
+ <c1>WHITE_KING</c1>
+ <b3>WHITE_QUEEN</b3>
+ <d1>WHITE_ROOK</d1>
+ <g5>WHITE_BISHOP</g5>
+ <a2>WHITE_PAWN</a2>
+ <b2>WHITE_PAWN</b2>
+ <c2>WHITE_PAWN</c2>
+ <e4>WHITE_PAWN</e4>
+ <f2>WHITE_PAWN</f2>
+ <g2>WHITE_PAWN</g2>
+ <h2>WHITE_PAWN</h2>
+ <e8>BLACK_KING</e8>
+ <e6>BLACK_QUEEN</e6>
+ <h8>BLACK_ROOK</h8>
+ <f8>BLACK_BISHOP</f8>
+ <d7>BLACK_KNIGHT</d7>
+ <a7>BLACK_PAWN</a7>
+ <e5>BLACK_PAWN</e5>
+ <f7>BLACK_PAWN</f7>
+ <g7>BLACK_PAWN</g7>
+ <h7>BLACK_PAWN</h7>
+ </squares>
+ <move>WHITE</move>
+ <castle>
+ <white>NONE</white>
+ <black>KING</black>
+ </castle>
+ <halfmove>0</halfmove>
+ <fullmove>16</fullmove>
+ </position>
+ </test>
+ <test>
+ <name>Immortal Game</name>
+ <fen>r1bk2nr/p2p1pNp/n2B4/1p1NP2P/6P1/3P1Q2/P1P1K3/q5b1 w - - 1 22</fen>
+ <position>
+ <squares>
+ <e2>WHITE_KING</e2>
+ <f3>WHITE_QUEEN</f3>
+ <d6>WHITE_BISHOP</d6>
+ <d5>WHITE_KNIGHT</d5>
+ <g7>WHITE_KNIGHT</g7>
+ <a2>WHITE_PAWN</a2>
+ <c2>WHITE_PAWN</c2>
+ <d3>WHITE_PAWN</d3>
+ <e5>WHITE_PAWN</e5>
+ <g4>WHITE_PAWN</g4>
+ <h5>WHITE_PAWN</h5>
+ <d8>BLACK_KING</d8>
+ <a1>BLACK_QUEEN</a1>
+ <a8>BLACK_ROOK</a8>
+ <h8>BLACK_ROOK</h8>
+ <c8>BLACK_BISHOP</c8>
+ <g1>BLACK_BISHOP</g1>
+ <a6>BLACK_KNIGHT</a6>
+ <g8>BLACK_KNIGHT</g8>
+ <a7>BLACK_PAWN</a7>
+ <b5>BLACK_PAWN</b5>
+ <d7>BLACK_PAWN</d7>
+ <f7>BLACK_PAWN</f7>
+ <h7>BLACK_PAWN</h7>
+ </squares>
+ <move>WHITE</move>
+ <castle>
+ <white>NONE</white>
+ <black>NONE</black>
+ </castle>
+ <halfmove>1</halfmove>
+ <fullmove>22</fullmove>
+ </position>
+ </test>
+ <test>
+ <name>Empty Position</name>
+ <fen>8/8/8/8/8/8/8/8 w - - 0 1</fen>
+ <position>
+ <empty>true</empty>
+ <move>WHITE</move>
+ <halfmove>0</halfmove>
+ <fullmove>1</fullmove>
+ </position>
+ </test>
+ </tests>
+</config>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+ ~ Copyright (c) 2018. Developed by Hedgecode.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<config>
+ <tests>
+ <test>
+ <name>Initial Position</name>
+ <fen>rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1</fen>
+ <position>
+ <initial>true</initial>
+ </position>
+ </test>
+ <test>
+ <name>Evergreen Game</name>
+ <fen>1r2k1r1/pbppnp1p/1b3P2/8/Q7/B1PB1q2/P4PPP/3R2K1 w - - 0 21</fen>
+ <position>
+ <squares>
+ <g1>WHITE_KING</g1>
+ <a4>WHITE_QUEEN</a4>
+ <d1>WHITE_ROOK</d1>
+ <a3>WHITE_BISHOP</a3>
+ <d3>WHITE_BISHOP</d3>
+ <a2>WHITE_PAWN</a2>
+ <c3>WHITE_PAWN</c3>
+ <f6>WHITE_PAWN</f6>
+ <f2>WHITE_PAWN</f2>
+ <g2>WHITE_PAWN</g2>
+ <h2>WHITE_PAWN</h2>
+ <e8>BLACK_KING</e8>
+ <f3>BLACK_QUEEN</f3>
+ <b8>BLACK_ROOK</b8>
+ <g8>BLACK_ROOK</g8>
+ <b7>BLACK_BISHOP</b7>
+ <b6>BLACK_BISHOP</b6>
+ <e7>BLACK_KNIGHT</e7>
+ <a7>BLACK_PAWN</a7>
+ <c7>BLACK_PAWN</c7>
+ <d7>BLACK_PAWN</d7>
+ <f7>BLACK_PAWN</f7>
+ <h7>BLACK_PAWN</h7>
+ </squares>
+ <move>WHITE</move>
+ <castle>
+ <white>NONE</white>
+ <black>NONE</black>
+ </castle>
+ <halfmove>0</halfmove>
+ <fullmove>21</fullmove>
+ </position>
+ </test>
+ <test>
+ <name>Immortal Zugzwang Game</name>
+ <fen>6k1/3q2p1/p2bp2p/3p1r2/1p1Pp3/3bQ1PP/PP1B1rB1/1N2R1RK w - - 0 26</fen>
+ <position>
+ <squares>
+ <h1>WHITE_KING</h1>
+ <e3>WHITE_QUEEN</e3>
+ <e1>WHITE_ROOK</e1>
+ <g1>WHITE_ROOK</g1>
+ <d2>WHITE_BISHOP</d2>
+ <g2>WHITE_BISHOP</g2>
+ <b1>WHITE_KNIGHT</b1>
+ <a2>WHITE_PAWN</a2>
+ <b2>WHITE_PAWN</b2>
+ <d4>WHITE_PAWN</d4>
+ <g3>WHITE_PAWN</g3>
+ <h3>WHITE_PAWN</h3>
+ <g8>BLACK_KING</g8>
+ <d7>BLACK_QUEEN</d7>
+ <f5>BLACK_ROOK</f5>
+ <f2>BLACK_ROOK</f2>
+ <d6>BLACK_BISHOP</d6>
+ <d3>BLACK_BISHOP</d3>
+ <a6>BLACK_PAWN</a6>
+ <b4>BLACK_PAWN</b4>
+ <d5>BLACK_PAWN</d5>
+ <e6>BLACK_PAWN</e6>
+ <e4>BLACK_PAWN</e4>
+ <g7>BLACK_PAWN</g7>
+ <h6>BLACK_PAWN</h6>
+ </squares>
+ <move>WHITE</move>
+ <castle>
+ <white>NONE</white>
+ <black>NONE</black>
+ </castle>
+ <halfmove>0</halfmove>
+ <fullmove>26</fullmove>
+ </position>
+ </test>
+ <test>
+ <name>Empty Position</name>
+ <fen>8/8/8/8/8/8/8/8 w - - 0 1</fen>
+ <position>
+ <empty>true</empty>
+ <move>WHITE</move>
+ <halfmove>0</halfmove>
+ <fullmove>1</fullmove>
+ </position>
+ </test>
+ </tests>
+</config>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+ ~ Copyright (c) 2018. Developed by Hedgecode.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<config>
+ <tests>
+ <test>
+ <name>Initial Position</name>
+ <tcd>xG</tcd>
+ <position>
+ <initial>true</initial>
+ </position>
+ </test>
+ <test>
+ <name>Morphy's Opera Game</name>
+ <tcd>AwNMIHJL1FdCEAVBGLvF+dnP4Xo6-hepgGH0yP0XP</tcd>
+ <position>
+ <squares>
+ <c1>WHITE_KING</c1>
+ <b3>WHITE_QUEEN</b3>
+ <d1>WHITE_ROOK</d1>
+ <g5>WHITE_BISHOP</g5>
+ <a2>WHITE_PAWN</a2>
+ <b2>WHITE_PAWN</b2>
+ <c2>WHITE_PAWN</c2>
+ <e4>WHITE_PAWN</e4>
+ <f2>WHITE_PAWN</f2>
+ <g2>WHITE_PAWN</g2>
+ <h2>WHITE_PAWN</h2>
+ <e8>BLACK_KING</e8>
+ <e6>BLACK_QUEEN</e6>
+ <h8>BLACK_ROOK</h8>
+ <f8>BLACK_BISHOP</f8>
+ <d7>BLACK_KNIGHT</d7>
+ <a7>BLACK_PAWN</a7>
+ <e5>BLACK_PAWN</e5>
+ <f7>BLACK_PAWN</f7>
+ <g7>BLACK_PAWN</g7>
+ <h7>BLACK_PAWN</h7>
+ </squares>
+ <move>WHITE</move>
+ <castle>
+ <white>NONE</white>
+ <black>KING</black>
+ </castle>
+ <halfmove>0</halfmove>
+ <fullmove>16</fullmove>
+ </position>
+ </test>
+ <test>
+ <name>Immortal Game</name>
+ <tcd></tcd>
+ <position>
+ <squares>
+ <e2>WHITE_KING</e2>
+ <f3>WHITE_QUEEN</f3>
+ <d6>WHITE_BISHOP</d6>
+ <d5>WHITE_KNIGHT</d5>
+ <g7>WHITE_KNIGHT</g7>
+ <a2>WHITE_PAWN</a2>
+ <c2>WHITE_PAWN</c2>
+ <d3>WHITE_PAWN</d3>
+ <e5>WHITE_PAWN</e5>
+ <g4>WHITE_PAWN</g4>
+ <h5>WHITE_PAWN</h5>
+ <d8>BLACK_KING</d8>
+ <a1>BLACK_QUEEN</a1>
+ <a8>BLACK_ROOK</a8>
+ <h8>BLACK_ROOK</h8>
+ <c8>BLACK_BISHOP</c8>
+ <g1>BLACK_BISHOP</g1>
+ <a6>BLACK_KNIGHT</a6>
+ <g8>BLACK_KNIGHT</g8>
+ <a7>BLACK_PAWN</a7>
+ <b5>BLACK_PAWN</b5>
+ <d7>BLACK_PAWN</d7>
+ <f7>BLACK_PAWN</f7>
+ <h7>BLACK_PAWN</h7>
+ </squares>
+ <move>WHITE</move>
+ <castle>
+ <white>NONE</white>
+ <black>NONE</black>
+ </castle>
+ <halfmove>1</halfmove>
+ <fullmove>22</fullmove>
+ </position>
+ </test>
+ <test>
+ <name>Reti's Etude</name>
+ <tcd></tcd>
+ <isDiagram>true</isDiagram>
+ <position>
+ <squares>
+ <h8>WHITE_KING</h8>
+ <c6>WHITE_PAWN</c6>
+ <a6>BLACK_KING</a6>
+ <h5>BLACK_PAWN</h5>
+ </squares>
+ </position>
+ </test>
+ <test>
+ <name>Empty Position</name>
+ <tcd>GG</tcd>
+ <isDiagram>true</isDiagram>
+ <position>
+ <empty>true</empty>
+ </position>
+ </test>
+ </tests>
+</config>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+ ~ Copyright (c) 2018. Developed by Hedgecode.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<config>
+ <tests>
+ <test>
+ <name>Initial Position</name>
+ <tcd>xG</tcd>
+ <position>
+ <initial>true</initial>
+ </position>
+ </test>
+ <test>
+ <name>Evergreen Game</name>
+ <tcd>AoJVMHMkKPTCE04FGLFV+4nPfYMNawOhjpgGH0xP0XU</tcd>
+ <position>
+ <squares>
+ <g1>WHITE_KING</g1>
+ <a4>WHITE_QUEEN</a4>
+ <d1>WHITE_ROOK</d1>
+ <a3>WHITE_BISHOP</a3>
+ <d3>WHITE_BISHOP</d3>
+ <a2>WHITE_PAWN</a2>
+ <c3>WHITE_PAWN</c3>
+ <f6>WHITE_PAWN</f6>
+ <f2>WHITE_PAWN</f2>
+ <g2>WHITE_PAWN</g2>
+ <h2>WHITE_PAWN</h2>
+ <e8>BLACK_KING</e8>
+ <f3>BLACK_QUEEN</f3>
+ <b8>BLACK_ROOK</b8>
+ <g8>BLACK_ROOK</g8>
+ <b7>BLACK_BISHOP</b7>
+ <b6>BLACK_BISHOP</b6>
+ <e7>BLACK_KNIGHT</e7>
+ <a7>BLACK_PAWN</a7>
+ <c7>BLACK_PAWN</c7>
+ <d7>BLACK_PAWN</d7>
+ <f7>BLACK_PAWN</f7>
+ <h7>BLACK_PAWN</h7>
+ </squares>
+ <move>WHITE</move>
+ <castle>
+ <white>NONE</white>
+ <black>NONE</black>
+ </castle>
+ <halfmove>0</halfmove>
+ <fullmove>21</fullmove>
+ </position>
+ </test>
+ <test>
+ <name>Immortal Zugzwang Game</name>
+ <tcd>AfSYHORACKNLLFEDVGGNvE9K2ecYZ3alih4pwGH0xP0XZ</tcd>
+ <position>
+ <squares>
+ <h1>WHITE_KING</h1>
+ <e3>WHITE_QUEEN</e3>
+ <e1>WHITE_ROOK</e1>
+ <g1>WHITE_ROOK</g1>
+ <d2>WHITE_BISHOP</d2>
+ <g2>WHITE_BISHOP</g2>
+ <b1>WHITE_KNIGHT</b1>
+ <a2>WHITE_PAWN</a2>
+ <b2>WHITE_PAWN</b2>
+ <d4>WHITE_PAWN</d4>
+ <g3>WHITE_PAWN</g3>
+ <h3>WHITE_PAWN</h3>
+ <g8>BLACK_KING</g8>
+ <d7>BLACK_QUEEN</d7>
+ <f5>BLACK_ROOK</f5>
+ <f2>BLACK_ROOK</f2>
+ <d6>BLACK_BISHOP</d6>
+ <d3>BLACK_BISHOP</d3>
+ <a6>BLACK_PAWN</a6>
+ <b4>BLACK_PAWN</b4>
+ <d5>BLACK_PAWN</d5>
+ <e6>BLACK_PAWN</e6>
+ <e4>BLACK_PAWN</e4>
+ <g7>BLACK_PAWN</g7>
+ <h6>BLACK_PAWN</h6>
+ </squares>
+ <move>WHITE</move>
+ <castle>
+ <white>NONE</white>
+ <black>NONE</black>
+ </castle>
+ <halfmove>0</halfmove>
+ <fullmove>26</fullmove>
+ </position>
+ </test>
+ <test>
+ <name>Reti's Etude Variation</name>
+ <tcd>ABnGgJv9mpEG</tcd>
+ <isDiagram>true</isDiagram>
+ <position>
+ <squares>
+ <h5>WHITE_KING</h5>
+ <c6>WHITE_PAWN</c6>
+ <a6>BLACK_KING</a6>
+ <f6>BLACK_PAWN</f6>
+ <g7>BLACK_PAWN</g7>
+ <h6>BLACK_PAWN</h6>
+ </squares>
+ </position>
+ </test>
+ <test>
+ <name>Empty Position</name>
+ <tcd>GG</tcd>
+ <isDiagram>true</isDiagram>
+ <position>
+ <empty>true</empty>
+ </position>
+ </test>
+ </tests>
+</config>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+ ~ Copyright (c) 2018. Developed by Hedgecode.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<config>
+ <tests>
+ <test>
+ <name>Initial Position</name>
+ <wiki>
+ <![CDATA[
+{{Шахматная диаграмма
+|
+|
+|rd|nd|bd|qd|kd|bd|nd|rd
+|pd|pd|pd|pd|pd|pd|pd|pd
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+|pl|pl|pl|pl|pl|pl|pl|pl
+|rl|nl|bl|ql|kl|bl|nl|rl
+|
+}}
+ ]]>
+ </wiki>
+ <withTemplate>true</withTemplate>
+ <position>
+ <initial>true</initial>
+ </position>
+ </test>
+ <test>
+ <name>Reti's Etude Variation</name>
+ <wiki>
+ <![CDATA[
+| | | | | | | |
+| | | | | | |pd|
+|kd| |pl| | |pd| |pd
+| | | | | | | |kl
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+ ]]>
+ </wiki>
+ <withTemplate>false</withTemplate>
+ <position>
+ <squares>
+ <h5>WHITE_KING</h5>
+ <c6>WHITE_PAWN</c6>
+ <a6>BLACK_KING</a6>
+ <f6>BLACK_PAWN</f6>
+ <g7>BLACK_PAWN</g7>
+ <h6>BLACK_PAWN</h6>
+ </squares>
+ <move>WHITE</move>
+ </position>
+ </test>
+ <test>
+ <name>Empty Position</name>
+ <wiki>
+ <![CDATA[
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+ ]]>
+ </wiki>
+ <position>
+ <empty>true</empty>
+ <move>WHITE</move>
+ </position>
+ </test>
+ </tests>
+</config>
--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+ ~ Copyright (c) 2018. Developed by Hedgecode.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<config>
+ <tests>
+ <test>
+ <name>Initial Position</name>
+ <wiki>
+ <![CDATA[
+|rd|nd|bd|qd|kd|bd|nd|rd
+|pd|pd|pd|pd|pd|pd|pd|pd
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+|pl|pl|pl|pl|pl|pl|pl|pl
+|rl|nl|bl|ql|kl|bl|nl|rl
+ ]]>
+ </wiki>
+ <withTemplate>false</withTemplate>
+ <position>
+ <initial>true</initial>
+ </position>
+ </test>
+ <test>
+ <name>Anderssen's Mate</name>
+ <wiki>
+ <![CDATA[
+| | | |bl|bl| | |kl
+| | | | | | | |pd
+| | | | | | | |kd
+| | | | | | | |
+| | | | | | | |
+| | | | | |pl| |pd
+| | | | | | | |pl
+| | | | | | | |
+ ]]>
+ </wiki>
+ <withTemplate>false</withTemplate>
+ <position>
+ <squares>
+ <h8>WHITE_KING</h8>
+ <d8>WHITE_BISHOP</d8>
+ <e8>WHITE_BISHOP</e8>
+ <f3>WHITE_PAWN</f3>
+ <h2>WHITE_PAWN</h2>
+ <h6>BLACK_KING</h6>
+ <h7>BLACK_PAWN</h7>
+ <h3>BLACK_PAWN</h3>
+ </squares>
+ <move>WHITE</move>
+ </position>
+ </test>
+ <test>
+ <name>Empty Position</name>
+ <wiki>
+ <![CDATA[
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+| | | | | | | |
+ ]]>
+ </wiki>
+ <position>
+ <empty>true</empty>
+ <move>WHITE</move>
+ </position>
+ </test>
+ </tests>
+</config>