From: gotty Date: Fri, 7 Dec 2018 19:39:58 +0000 (+0300) Subject: [LIB-9] Add original chesshog source files X-Git-Url: https://git.hedgecode.org/?a=commitdiff_plain;h=d290e40e310fc81ee8ccaf98c2d4cec017561151;p=chesshog.git [LIB-9] Add original chesshog source files --- d290e40e310fc81ee8ccaf98c2d4cec017561151 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..55e3409 --- /dev/null +++ b/pom.xml @@ -0,0 +1,236 @@ + + + + + + 4.0.0 + + + org.hedgecode.maven + lib-parent + 2 + ../lib-parent/pom.xml + + + org.hedgecode.chess + chesshog + 0.1-SNAPSHOT + jar + + Hedgecode Chess + + Hedgecode Chess. + + 2018 + + http://lib.hedgecode.org/${project.artifactId}/ + + + scm:svn:http://svn.hedgecode.org/lib/${project.artifactId}/trunk/ + scm:svn:https://svn.hedgecode.org/lib/${project.artifactId}/trunk/ + http://svn.hedgecode.org/lib/${project.artifactId}/trunk/ + + + + JIRA + http://issues.hedgecode.org/browse/${issueKey}/component/${issueComponentId} + + + + + hedgecode.website + Hedgecode Libs Website + dav:https://hedgecode.org/libs/${project.artifactId}/ + + + + + 4.12 + 1.10 + 3.2.1 + 2.8 + 2.4.1 + 10030 + 9 + + + + + junit + junit + ${junitVersion} + test + + + commons-configuration + commons-configuration + ${commonsConfigVersion} + test + + + commons-collections + commons-collections + ${commonsCollectionVersion} + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + ${mavenDependencyPluginVersion} + + + copy-dependencies + prepare-package + + copy-dependencies + + + ${project.build.directory}/lib + false + false + true + + + + + + org.apache.maven.plugins + maven-jar-plugin + ${mavenJarPluginVersion} + + + + true + lib/ + true + true + org.hedgecode.chess.ChessHogApp + + + ${project.artifactId} + + + + + + org.apache.maven.plugins + maven-release-plugin + ${mavenReleasePluginVersion} + + https://svn.hedgecode.org/lib/${project.artifactId}/tags + https://svn.hedgecode.org/lib/${project.artifactId}/branches + clean install + deploy + release + [${issueKey}-${issueNumber}] + + + + + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + ${mavenReportsPluginVersion} + + false + + + + + index + summary + dependency-info + project-team + scm + dependency-management + dependencies + plugin-management + plugins + distribution-management + + + + + + + + + + jar-with-dependencies + + + + org.apache.maven.plugins + maven-assembly-plugin + ${mavenAssemblyPluginVersion} + + + + true + lib/ + true + true + org.hedgecode.chess.ChessHogApp + + + ${project.artifactId} + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + + + reporting + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + + + + + + + + + + diff --git a/src/main/java/org/hedgecode/chess/Builders.java b/src/main/java/org/hedgecode/chess/Builders.java new file mode 100644 index 0000000..94e2a91 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/Builders.java @@ -0,0 +1,47 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/ChessHogApp.java b/src/main/java/org/hedgecode/chess/ChessHogApp.java new file mode 100644 index 0000000..94dfaa0 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/ChessHogApp.java @@ -0,0 +1,31 @@ +/* + * 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 diff --git a/src/main/java/org/hedgecode/chess/ChessHogConstants.java b/src/main/java/org/hedgecode/chess/ChessHogConstants.java new file mode 100644 index 0000000..77d1d95 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/ChessHogConstants.java @@ -0,0 +1,41 @@ +/* + * 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!" + ); + } + +} diff --git a/src/main/java/org/hedgecode/chess/Parsers.java b/src/main/java/org/hedgecode/chess/Parsers.java new file mode 100644 index 0000000..ac5ed91 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/Parsers.java @@ -0,0 +1,47 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/ascii/ASCII.java b/src/main/java/org/hedgecode/chess/ascii/ASCII.java new file mode 100644 index 0000000..c8467c1 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/ascii/ASCII.java @@ -0,0 +1,142 @@ +/* + * 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 PIECES = new HashMap() { + { + 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 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 diff --git a/src/main/java/org/hedgecode/chess/ascii/ASCIIBoardType.java b/src/main/java/org/hedgecode/chess/ascii/ASCIIBoardType.java new file mode 100644 index 0000000..08428b8 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/ascii/ASCIIBoardType.java @@ -0,0 +1,96 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/ascii/ASCIIBuilder.java b/src/main/java/org/hedgecode/chess/ascii/ASCIIBuilder.java new file mode 100644 index 0000000..54599bb --- /dev/null +++ b/src/main/java/org/hedgecode/chess/ascii/ASCIIBuilder.java @@ -0,0 +1,166 @@ +/* + * 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 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()) + ); +*/ + } + +} diff --git a/src/main/java/org/hedgecode/chess/ascii/ASCIIParser.java b/src/main/java/org/hedgecode/chess/ascii/ASCIIParser.java new file mode 100644 index 0000000..65fa3e0 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/ascii/ASCIIParser.java @@ -0,0 +1,158 @@ +/* + * 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 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 + ); + } + +} diff --git a/src/main/java/org/hedgecode/chess/fen/FEN.java b/src/main/java/org/hedgecode/chess/fen/FEN.java new file mode 100644 index 0000000..5145ae4 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/fen/FEN.java @@ -0,0 +1,203 @@ +/* + * 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 COLORS = new HashMap() { + { + put(Color.WHITE, WHITE); + put(Color.BLACK, BLACK); + } + }; + + private static final Map PIECES = new HashMap() { + { + 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 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 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); + } + +} diff --git a/src/main/java/org/hedgecode/chess/fen/FENBuilder.java b/src/main/java/org/hedgecode/chess/fen/FENBuilder.java new file mode 100644 index 0000000..d63bb93 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/fen/FENBuilder.java @@ -0,0 +1,126 @@ +/* + * 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 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) + ); + + } + +} diff --git a/src/main/java/org/hedgecode/chess/fen/FENParser.java b/src/main/java/org/hedgecode/chess/fen/FENParser.java new file mode 100644 index 0000000..4162a55 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/fen/FENParser.java @@ -0,0 +1,193 @@ +/* + * 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); + } + +} diff --git a/src/main/java/org/hedgecode/chess/game/AbstractMove.java b/src/main/java/org/hedgecode/chess/game/AbstractMove.java new file mode 100644 index 0000000..a417325 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/game/AbstractMove.java @@ -0,0 +1,53 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/game/Game.java b/src/main/java/org/hedgecode/chess/game/Game.java new file mode 100644 index 0000000..b50a71f --- /dev/null +++ b/src/main/java/org/hedgecode/chess/game/Game.java @@ -0,0 +1,29 @@ +/* + * 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(); + + +} diff --git a/src/main/java/org/hedgecode/chess/game/GameMove.java b/src/main/java/org/hedgecode/chess/game/GameMove.java new file mode 100644 index 0000000..392e58a --- /dev/null +++ b/src/main/java/org/hedgecode/chess/game/GameMove.java @@ -0,0 +1,64 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/game/GameMoves.java b/src/main/java/org/hedgecode/chess/game/GameMoves.java new file mode 100644 index 0000000..75c303d --- /dev/null +++ b/src/main/java/org/hedgecode/chess/game/GameMoves.java @@ -0,0 +1,97 @@ +/* + * 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 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); + } + + } + +} diff --git a/src/main/java/org/hedgecode/chess/game/Move.java b/src/main/java/org/hedgecode/chess/game/Move.java new file mode 100644 index 0000000..16d3bd8 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/game/Move.java @@ -0,0 +1,44 @@ +/* + * 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(); + +} diff --git a/src/main/java/org/hedgecode/chess/game/Moves.java b/src/main/java/org/hedgecode/chess/game/Moves.java new file mode 100644 index 0000000..e4d69c2 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/game/Moves.java @@ -0,0 +1,42 @@ +/* + * 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); + +} diff --git a/src/main/java/org/hedgecode/chess/hedgefish/HedgefishCommand.java b/src/main/java/org/hedgecode/chess/hedgefish/HedgefishCommand.java new file mode 100644 index 0000000..c64c7c3 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/hedgefish/HedgefishCommand.java @@ -0,0 +1,36 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/hedgefish/HedgefishEngine.java b/src/main/java/org/hedgecode/chess/hedgefish/HedgefishEngine.java new file mode 100644 index 0000000..fc79b78 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/hedgefish/HedgefishEngine.java @@ -0,0 +1,85 @@ +/* + * 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 transmitter; + + private DebugMode debugMode; + + HedgefishEngine() { + transmitter = new HedgefishTransmitter(); + debugMode = DebugMode.OFF; + } + + public Transmitter 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(); + } + +} diff --git a/src/main/java/org/hedgecode/chess/hedgefish/HedgefishEngineRunner.java b/src/main/java/org/hedgecode/chess/hedgefish/HedgefishEngineRunner.java new file mode 100644 index 0000000..0eaedc6 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/hedgefish/HedgefishEngineRunner.java @@ -0,0 +1,84 @@ +/* + * 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 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/hedgefish/HedgefishTransmitter.java b/src/main/java/org/hedgecode/chess/hedgefish/HedgefishTransmitter.java new file mode 100644 index 0000000..a945b02 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/hedgefish/HedgefishTransmitter.java @@ -0,0 +1,65 @@ +/* + * 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 { + + private Queue 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/hedgefish/Types.java b/src/main/java/org/hedgecode/chess/hedgefish/Types.java new file mode 100644 index 0000000..7221c79 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/hedgefish/Types.java @@ -0,0 +1,103 @@ +/* + * 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 + } + +// ... + +} diff --git a/src/main/java/org/hedgecode/chess/hedgefish/UCI.java b/src/main/java/org/hedgecode/chess/hedgefish/UCI.java new file mode 100644 index 0000000..69fa4a1 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/hedgefish/UCI.java @@ -0,0 +1,56 @@ +/* + * 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) { + + } + + } + +} diff --git a/src/main/java/org/hedgecode/chess/img/DiagramBuilder.java b/src/main/java/org/hedgecode/chess/img/DiagramBuilder.java new file mode 100644 index 0000000..17ff21a --- /dev/null +++ b/src/main/java/org/hedgecode/chess/img/DiagramBuilder.java @@ -0,0 +1,96 @@ +/* + * 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 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); + } + +} diff --git a/src/main/java/org/hedgecode/chess/img/ImageBuilder.java b/src/main/java/org/hedgecode/chess/img/ImageBuilder.java new file mode 100644 index 0000000..45537d5 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/img/ImageBuilder.java @@ -0,0 +1,35 @@ +/* + * 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); + +} diff --git a/src/main/java/org/hedgecode/chess/img/ImageFormat.java b/src/main/java/org/hedgecode/chess/img/ImageFormat.java new file mode 100644 index 0000000..26954ab --- /dev/null +++ b/src/main/java/org/hedgecode/chess/img/ImageFormat.java @@ -0,0 +1,96 @@ +/* + * 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 diff --git a/src/main/java/org/hedgecode/chess/pgn/PGNBuilder.java b/src/main/java/org/hedgecode/chess/pgn/PGNBuilder.java new file mode 100644 index 0000000..7095a56 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/pgn/PGNBuilder.java @@ -0,0 +1,29 @@ +/* + * 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 { + + + + +} diff --git a/src/main/java/org/hedgecode/chess/pgn/PGNParser.java b/src/main/java/org/hedgecode/chess/pgn/PGNParser.java new file mode 100644 index 0000000..274bfdf --- /dev/null +++ b/src/main/java/org/hedgecode/chess/pgn/PGNParser.java @@ -0,0 +1,28 @@ +/* + * 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 { + + + +} diff --git a/src/main/java/org/hedgecode/chess/position/Builder.java b/src/main/java/org/hedgecode/chess/position/Builder.java new file mode 100644 index 0000000..ce09887 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/position/Builder.java @@ -0,0 +1,28 @@ +/* + * 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); + +} diff --git a/src/main/java/org/hedgecode/chess/position/Castle.java b/src/main/java/org/hedgecode/chess/position/Castle.java new file mode 100644 index 0000000..c18be1d --- /dev/null +++ b/src/main/java/org/hedgecode/chess/position/Castle.java @@ -0,0 +1,31 @@ +/* + * 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 + +} diff --git a/src/main/java/org/hedgecode/chess/position/Color.java b/src/main/java/org/hedgecode/chess/position/Color.java new file mode 100644 index 0000000..742dc0d --- /dev/null +++ b/src/main/java/org/hedgecode/chess/position/Color.java @@ -0,0 +1,29 @@ +/* + * 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 + +} diff --git a/src/main/java/org/hedgecode/chess/position/ColorPiece.java b/src/main/java/org/hedgecode/chess/position/ColorPiece.java new file mode 100644 index 0000000..77fa7a4 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/position/ColorPiece.java @@ -0,0 +1,66 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/position/DiagramPosition.java b/src/main/java/org/hedgecode/chess/position/DiagramPosition.java new file mode 100644 index 0000000..e12b477 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/position/DiagramPosition.java @@ -0,0 +1,198 @@ +/* + * 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 squares = new HashMap() { + { + 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 getSquares() { + return squares; + } + + @Override + public Map getSquarePieces(Color color) { + return getSquarePieces(color, null); + } + + @Override + public Map getSquarePieces(Color color, Piece piece) { + Map squarePieces = new HashMap<>(); + for (Map.Entry 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 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); + } + + } + +} diff --git a/src/main/java/org/hedgecode/chess/position/GamePosition.java b/src/main/java/org/hedgecode/chess/position/GamePosition.java new file mode 100644 index 0000000..42f9ae2 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/position/GamePosition.java @@ -0,0 +1,86 @@ +/* + * 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 castles = new HashMap(){ + { + 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/position/ParseException.java b/src/main/java/org/hedgecode/chess/position/ParseException.java new file mode 100644 index 0000000..ac1b911 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/position/ParseException.java @@ -0,0 +1,58 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/position/Parser.java b/src/main/java/org/hedgecode/chess/position/Parser.java new file mode 100644 index 0000000..ae448ae --- /dev/null +++ b/src/main/java/org/hedgecode/chess/position/Parser.java @@ -0,0 +1,28 @@ +/* + * 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; + +} diff --git a/src/main/java/org/hedgecode/chess/position/Piece.java b/src/main/java/org/hedgecode/chess/position/Piece.java new file mode 100644 index 0000000..9554606 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/position/Piece.java @@ -0,0 +1,61 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/position/Position.java b/src/main/java/org/hedgecode/chess/position/Position.java new file mode 100644 index 0000000..6fd9713 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/position/Position.java @@ -0,0 +1,93 @@ +/* + * 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 getSquares(); + + Map getSquarePieces(Color color); + + Map 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); + } + +} diff --git a/src/main/java/org/hedgecode/chess/position/PositionType.java b/src/main/java/org/hedgecode/chess/position/PositionType.java new file mode 100644 index 0000000..0fdd4fe --- /dev/null +++ b/src/main/java/org/hedgecode/chess/position/PositionType.java @@ -0,0 +1,29 @@ +/* + * 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 + +} diff --git a/src/main/java/org/hedgecode/chess/position/Positions.java b/src/main/java/org/hedgecode/chess/position/Positions.java new file mode 100644 index 0000000..f5071e2 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/position/Positions.java @@ -0,0 +1,74 @@ +/* + * 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(); + +} diff --git a/src/main/java/org/hedgecode/chess/position/Square.java b/src/main/java/org/hedgecode/chess/position/Square.java new file mode 100644 index 0000000..df752a2 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/position/Square.java @@ -0,0 +1,73 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/tcd/TCD.java b/src/main/java/org/hedgecode/chess/tcd/TCD.java new file mode 100644 index 0000000..2d900c8 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/tcd/TCD.java @@ -0,0 +1,160 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/tcd/TCDBuilder.java b/src/main/java/org/hedgecode/chess/tcd/TCDBuilder.java new file mode 100644 index 0000000..bc37d20 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/tcd/TCDBuilder.java @@ -0,0 +1,362 @@ +/* + * 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 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()) + ); +*/ + } + +} diff --git a/src/main/java/org/hedgecode/chess/tcd/TCDParser.java b/src/main/java/org/hedgecode/chess/tcd/TCDParser.java new file mode 100644 index 0000000..bcf1989 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/tcd/TCDParser.java @@ -0,0 +1,268 @@ +/* + * 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); + } + +} diff --git a/src/main/java/org/hedgecode/chess/tcg/TCG.java b/src/main/java/org/hedgecode/chess/tcg/TCG.java new file mode 100644 index 0000000..d1f7742 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/tcg/TCG.java @@ -0,0 +1,41 @@ +/* + * 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() { + } + + +} diff --git a/src/main/java/org/hedgecode/chess/tcg/TCGBuilder.java b/src/main/java/org/hedgecode/chess/tcg/TCGBuilder.java new file mode 100644 index 0000000..f1f32ba --- /dev/null +++ b/src/main/java/org/hedgecode/chess/tcg/TCGBuilder.java @@ -0,0 +1,26 @@ +/* + * 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 { + +} diff --git a/src/main/java/org/hedgecode/chess/tcg/TCGParser.java b/src/main/java/org/hedgecode/chess/tcg/TCGParser.java new file mode 100644 index 0000000..0a5c819 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/tcg/TCGParser.java @@ -0,0 +1,26 @@ +/* + * 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 { + +} diff --git a/src/main/java/org/hedgecode/chess/uci/Acceptor.java b/src/main/java/org/hedgecode/chess/uci/Acceptor.java new file mode 100644 index 0000000..4dc2e84 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/Acceptor.java @@ -0,0 +1,44 @@ +/* + * 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 vars); + + void terminate(String params); + +} diff --git a/src/main/java/org/hedgecode/chess/uci/AcceptorException.java b/src/main/java/org/hedgecode/chess/uci/AcceptorException.java new file mode 100644 index 0000000..f19da9a --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/AcceptorException.java @@ -0,0 +1,61 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/AcceptorRunner.java b/src/main/java/org/hedgecode/chess/uci/AcceptorRunner.java new file mode 100644 index 0000000..138f202 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/AcceptorRunner.java @@ -0,0 +1,32 @@ +/* + * 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 { + + @Override + Acceptor init() throws AcceptorException; + + @Override + void run(CommandExecutor commandExecutor) throws AcceptorException; + +} diff --git a/src/main/java/org/hedgecode/chess/uci/AcceptorStub.java b/src/main/java/org/hedgecode/chess/uci/AcceptorStub.java new file mode 100644 index 0000000..c667a7d --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/AcceptorStub.java @@ -0,0 +1,161 @@ +/* + * 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 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() + ); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/AcceptorStubRunner.java b/src/main/java/org/hedgecode/chess/uci/AcceptorStubRunner.java new file mode 100644 index 0000000..8f8ad14 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/AcceptorStubRunner.java @@ -0,0 +1,43 @@ +/* + * 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(); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/CommandDescriptor.java b/src/main/java/org/hedgecode/chess/uci/CommandDescriptor.java new file mode 100644 index 0000000..db88dfb --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/CommandDescriptor.java @@ -0,0 +1,160 @@ +/* + * 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 commandsTo = new HashMap<>(); + private Map 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 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 findCommands(File dir, String packageName) throws Exception { + List 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); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/CommandEnvironment.java b/src/main/java/org/hedgecode/chess/uci/CommandEnvironment.java new file mode 100644 index 0000000..348a902 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/CommandEnvironment.java @@ -0,0 +1,51 @@ +/* + * 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(); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/CommandException.java b/src/main/java/org/hedgecode/chess/uci/CommandException.java new file mode 100644 index 0000000..032b36c --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/CommandException.java @@ -0,0 +1,28 @@ +/* + * 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 { + + + +} diff --git a/src/main/java/org/hedgecode/chess/uci/CommandExecutor.java b/src/main/java/org/hedgecode/chess/uci/CommandExecutor.java new file mode 100644 index 0000000..9de15df --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/CommandExecutor.java @@ -0,0 +1,30 @@ +/* + * 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); + +} diff --git a/src/main/java/org/hedgecode/chess/uci/ConsoleAcceptor.java b/src/main/java/org/hedgecode/chess/uci/ConsoleAcceptor.java new file mode 100644 index 0000000..028cdaf --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/ConsoleAcceptor.java @@ -0,0 +1,181 @@ +/* + * 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 { + + 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 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 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() + ); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/ConsoleAcceptorRunner.java b/src/main/java/org/hedgecode/chess/uci/ConsoleAcceptorRunner.java new file mode 100644 index 0000000..d699eed --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/ConsoleAcceptorRunner.java @@ -0,0 +1,91 @@ +/* + * 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 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/DebugMode.java b/src/main/java/org/hedgecode/chess/uci/DebugMode.java new file mode 100644 index 0000000..820da33 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/DebugMode.java @@ -0,0 +1,41 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/Engine.java b/src/main/java/org/hedgecode/chess/uci/Engine.java new file mode 100644 index 0000000..0ee971f --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/Engine.java @@ -0,0 +1,40 @@ +/* + * 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(); + +} diff --git a/src/main/java/org/hedgecode/chess/uci/EngineException.java b/src/main/java/org/hedgecode/chess/uci/EngineException.java new file mode 100644 index 0000000..c48ec3c --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/EngineException.java @@ -0,0 +1,61 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/EngineRunner.java b/src/main/java/org/hedgecode/chess/uci/EngineRunner.java new file mode 100644 index 0000000..af8ce5a --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/EngineRunner.java @@ -0,0 +1,32 @@ +/* + * 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 { + + @Override + Engine init() throws EngineException; + + @Override + void run(CommandExecutor commandExecutor) throws EngineException; + +} diff --git a/src/main/java/org/hedgecode/chess/uci/ExternalEngine.java b/src/main/java/org/hedgecode/chess/uci/ExternalEngine.java new file mode 100644 index 0000000..7b09fb5 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/ExternalEngine.java @@ -0,0 +1,104 @@ +/* + * 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 + ); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/ExternalEngineRunner.java b/src/main/java/org/hedgecode/chess/uci/ExternalEngineRunner.java new file mode 100644 index 0000000..fd81352 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/ExternalEngineRunner.java @@ -0,0 +1,174 @@ +/* + * 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 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 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(); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/Receiver.java b/src/main/java/org/hedgecode/chess/uci/Receiver.java new file mode 100644 index 0000000..e135642 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/Receiver.java @@ -0,0 +1,36 @@ +/* + * 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 { + + boolean isActive(); + + boolean hasCommand(); + + T receiveCommand(); + + void stop(); + + void close(); + +} diff --git a/src/main/java/org/hedgecode/chess/uci/Runner.java b/src/main/java/org/hedgecode/chess/uci/Runner.java new file mode 100644 index 0000000..7e466ed --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/Runner.java @@ -0,0 +1,30 @@ +/* + * 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 init() throws E; + + void run(CommandExecutor commandExecutor) throws E; + +} diff --git a/src/main/java/org/hedgecode/chess/uci/SyncCommandExecutor.java b/src/main/java/org/hedgecode/chess/uci/SyncCommandExecutor.java new file mode 100644 index 0000000..cb024de --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/SyncCommandExecutor.java @@ -0,0 +1,69 @@ +/* + * 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); + } + + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/Transmitter.java b/src/main/java/org/hedgecode/chess/uci/Transmitter.java new file mode 100644 index 0000000..d030563 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/Transmitter.java @@ -0,0 +1,36 @@ +/* + * 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 { + + boolean isActive(); + + boolean hasCommand(); + + T transmitCommand(); + + void addCommand(T command); + + void stop(); + +} diff --git a/src/main/java/org/hedgecode/chess/uci/UCICommand.java b/src/main/java/org/hedgecode/chess/uci/UCICommand.java new file mode 100644 index 0000000..b5b7d65 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/UCICommand.java @@ -0,0 +1,28 @@ +/* + * 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); + +} diff --git a/src/main/java/org/hedgecode/chess/uci/UCIConstants.java b/src/main/java/org/hedgecode/chess/uci/UCIConstants.java new file mode 100644 index 0000000..e8e1bfc --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/UCIConstants.java @@ -0,0 +1,65 @@ +/* + * 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!" + ); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/annotation/Command.java b/src/main/java/org/hedgecode/chess/uci/annotation/Command.java new file mode 100644 index 0000000..7c086b4 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/annotation/Command.java @@ -0,0 +1,37 @@ +/* + * 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(); + +} diff --git a/src/main/java/org/hedgecode/chess/uci/annotation/CommandDirection.java b/src/main/java/org/hedgecode/chess/uci/annotation/CommandDirection.java new file mode 100644 index 0000000..fde12b8 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/annotation/CommandDirection.java @@ -0,0 +1,34 @@ +/* + * 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 +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/AbstractCommand.java b/src/main/java/org/hedgecode/chess/uci/command/AbstractCommand.java new file mode 100644 index 0000000..0f65888 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/AbstractCommand.java @@ -0,0 +1,58 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/CommandParams.java b/src/main/java/org/hedgecode/chess/uci/command/CommandParams.java new file mode 100644 index 0000000..4baf6b7 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/CommandParams.java @@ -0,0 +1,47 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/InfoParams.java b/src/main/java/org/hedgecode/chess/uci/command/InfoParams.java new file mode 100644 index 0000000..c4d67d4 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/InfoParams.java @@ -0,0 +1,27 @@ +/* + * 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 { + + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/Move.java b/src/main/java/org/hedgecode/chess/uci/command/Move.java new file mode 100644 index 0000000..441e2f9 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/Move.java @@ -0,0 +1,72 @@ +/* + * 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/OptionParams.java b/src/main/java/org/hedgecode/chess/uci/command/OptionParams.java new file mode 100644 index 0000000..cb677e3 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/OptionParams.java @@ -0,0 +1,200 @@ +/* + * 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 = ""; + + 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 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 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 ", + "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); + } + } + + + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/OptionType.java b/src/main/java/org/hedgecode/chess/uci/command/OptionType.java new file mode 100644 index 0000000..fc91c6a --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/OptionType.java @@ -0,0 +1,69 @@ +/* + * 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 "". + */ + 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/from/BestMoveCommand.java b/src/main/java/org/hedgecode/chess/uci/command/from/BestMoveCommand.java new file mode 100644 index 0000000..1a9b982 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/from/BestMoveCommand.java @@ -0,0 +1,43 @@ +/* + * 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) { + + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/from/CopyProtectionCommand.java b/src/main/java/org/hedgecode/chess/uci/command/from/CopyProtectionCommand.java new file mode 100644 index 0000000..5bae74c --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/from/CopyProtectionCommand.java @@ -0,0 +1,43 @@ +/* + * 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) { + + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/from/IdCommand.java b/src/main/java/org/hedgecode/chess/uci/command/from/IdCommand.java new file mode 100644 index 0000000..167ba05 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/from/IdCommand.java @@ -0,0 +1,43 @@ +/* + * 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); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/from/InfoCommand.java b/src/main/java/org/hedgecode/chess/uci/command/from/InfoCommand.java new file mode 100644 index 0000000..453463d --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/from/InfoCommand.java @@ -0,0 +1,43 @@ +/* + * 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) { + + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/from/OkCommand.java b/src/main/java/org/hedgecode/chess/uci/command/from/OkCommand.java new file mode 100644 index 0000000..44d0b99 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/from/OkCommand.java @@ -0,0 +1,43 @@ +/* + * 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); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/from/OptionCommand.java b/src/main/java/org/hedgecode/chess/uci/command/from/OptionCommand.java new file mode 100644 index 0000000..080d143 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/from/OptionCommand.java @@ -0,0 +1,80 @@ +/* + * 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; + } + } + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/from/ReadyOkCommand.java b/src/main/java/org/hedgecode/chess/uci/command/from/ReadyOkCommand.java new file mode 100644 index 0000000..225e7e4 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/from/ReadyOkCommand.java @@ -0,0 +1,43 @@ +/* + * 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); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/from/RegistrationCommand.java b/src/main/java/org/hedgecode/chess/uci/command/from/RegistrationCommand.java new file mode 100644 index 0000000..1ba791d --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/from/RegistrationCommand.java @@ -0,0 +1,43 @@ +/* + * 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) { + + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/from/TerminateCommand.java b/src/main/java/org/hedgecode/chess/uci/command/from/TerminateCommand.java new file mode 100644 index 0000000..299184e --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/from/TerminateCommand.java @@ -0,0 +1,43 @@ +/* + * 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); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/to/DebugCommand.java b/src/main/java/org/hedgecode/chess/uci/command/to/DebugCommand.java new file mode 100644 index 0000000..558ede9 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/to/DebugCommand.java @@ -0,0 +1,45 @@ +/* + * 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 + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/to/GoCommand.java b/src/main/java/org/hedgecode/chess/uci/command/to/GoCommand.java new file mode 100644 index 0000000..45edc58 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/to/GoCommand.java @@ -0,0 +1,43 @@ +/* + * 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) { + + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/to/InitCommand.java b/src/main/java/org/hedgecode/chess/uci/command/to/InitCommand.java new file mode 100644 index 0000000..870a535 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/to/InitCommand.java @@ -0,0 +1,43 @@ +/* + * 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(); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/to/IsReadyCommand.java b/src/main/java/org/hedgecode/chess/uci/command/to/IsReadyCommand.java new file mode 100644 index 0000000..47b32c2 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/to/IsReadyCommand.java @@ -0,0 +1,43 @@ +/* + * 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(); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/to/NewGameCommand.java b/src/main/java/org/hedgecode/chess/uci/command/to/NewGameCommand.java new file mode 100644 index 0000000..ea44bbc --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/to/NewGameCommand.java @@ -0,0 +1,43 @@ +/* + * 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) { + + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/to/PonderHitCommand.java b/src/main/java/org/hedgecode/chess/uci/command/to/PonderHitCommand.java new file mode 100644 index 0000000..b3922cc --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/to/PonderHitCommand.java @@ -0,0 +1,43 @@ +/* + * 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) { + + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/to/PositionCommand.java b/src/main/java/org/hedgecode/chess/uci/command/to/PositionCommand.java new file mode 100644 index 0000000..981f580 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/to/PositionCommand.java @@ -0,0 +1,43 @@ +/* + * 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) { + + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/to/QuitCommand.java b/src/main/java/org/hedgecode/chess/uci/command/to/QuitCommand.java new file mode 100644 index 0000000..0d5a474 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/to/QuitCommand.java @@ -0,0 +1,43 @@ +/* + * 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(); + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/to/RegisterCommand.java b/src/main/java/org/hedgecode/chess/uci/command/to/RegisterCommand.java new file mode 100644 index 0000000..05c34ae --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/to/RegisterCommand.java @@ -0,0 +1,43 @@ +/* + * 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) { + + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/to/SetOptionCommand.java b/src/main/java/org/hedgecode/chess/uci/command/to/SetOptionCommand.java new file mode 100644 index 0000000..070c8ec --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/to/SetOptionCommand.java @@ -0,0 +1,43 @@ +/* + * 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) { + + } + +} diff --git a/src/main/java/org/hedgecode/chess/uci/command/to/StopCommand.java b/src/main/java/org/hedgecode/chess/uci/command/to/StopCommand.java new file mode 100644 index 0000000..102c7b6 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/uci/command/to/StopCommand.java @@ -0,0 +1,43 @@ +/* + * 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(); + } + +} diff --git a/src/main/java/org/hedgecode/chess/wiki/Wiki.java b/src/main/java/org/hedgecode/chess/wiki/Wiki.java new file mode 100644 index 0000000..93819d6 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/wiki/Wiki.java @@ -0,0 +1,101 @@ +/* + * 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 PIECES = new HashMap() { + { + 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 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; + } + +} diff --git a/src/main/java/org/hedgecode/chess/wiki/WikiBuilder.java b/src/main/java/org/hedgecode/chess/wiki/WikiBuilder.java new file mode 100644 index 0000000..cf26552 --- /dev/null +++ b/src/main/java/org/hedgecode/chess/wiki/WikiBuilder.java @@ -0,0 +1,106 @@ +/* + * 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 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) + ); + } + +} diff --git a/src/main/java/org/hedgecode/chess/wiki/WikiParser.java b/src/main/java/org/hedgecode/chess/wiki/WikiParser.java new file mode 100644 index 0000000..93d7ffa --- /dev/null +++ b/src/main/java/org/hedgecode/chess/wiki/WikiParser.java @@ -0,0 +1,117 @@ +/* + * 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 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); + } + +} diff --git a/src/main/resources/org/hedgecode/chess/LocalStrings.properties b/src/main/resources/org/hedgecode/chess/LocalStrings.properties new file mode 100644 index 0000000..66a5a66 --- /dev/null +++ b/src/main/resources/org/hedgecode/chess/LocalStrings.properties @@ -0,0 +1,31 @@ +# 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 diff --git a/src/main/resources/org/hedgecode/chess/LocalStrings_ru.properties b/src/main/resources/org/hedgecode/chess/LocalStrings_ru.properties new file mode 100644 index 0000000..05dad64 --- /dev/null +++ b/src/main/resources/org/hedgecode/chess/LocalStrings_ru.properties @@ -0,0 +1,30 @@ +# 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 diff --git a/src/main/resources/org/hedgecode/chess/uci/LocalStrings.properties b/src/main/resources/org/hedgecode/chess/uci/LocalStrings.properties new file mode 100644 index 0000000..c3f9a7c --- /dev/null +++ b/src/main/resources/org/hedgecode/chess/uci/LocalStrings.properties @@ -0,0 +1,22 @@ +# 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 diff --git a/src/main/resources/org/hedgecode/chess/uci/LocalStrings_ru.properties b/src/main/resources/org/hedgecode/chess/uci/LocalStrings_ru.properties new file mode 100644 index 0000000..3a7ce0d --- /dev/null +++ b/src/main/resources/org/hedgecode/chess/uci/LocalStrings_ru.properties @@ -0,0 +1,21 @@ +# 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 diff --git a/src/test/java/org/hedgecode/chess/AbstractPositionTest.java b/src/test/java/org/hedgecode/chess/AbstractPositionTest.java new file mode 100644 index 0000000..6aa3f74 --- /dev/null +++ b/src/test/java/org/hedgecode/chess/AbstractPositionTest.java @@ -0,0 +1,316 @@ +/* + * 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 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 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 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 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 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 expected, Map actual) { + for (Map.Entry 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) + ); + } + } +*/ + +} diff --git a/src/test/java/org/hedgecode/chess/AbstractXMLConfigTest.java b/src/test/java/org/hedgecode/chess/AbstractXMLConfigTest.java new file mode 100644 index 0000000..e27274a --- /dev/null +++ b/src/test/java/org/hedgecode/chess/AbstractXMLConfigTest.java @@ -0,0 +1,79 @@ +/* + * 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 diff --git a/src/test/java/org/hedgecode/chess/ascii/ASCIIBuilderTest.java b/src/test/java/org/hedgecode/chess/ascii/ASCIIBuilderTest.java new file mode 100644 index 0000000..7c96f14 --- /dev/null +++ b/src/test/java/org/hedgecode/chess/ascii/ASCIIBuilderTest.java @@ -0,0 +1,106 @@ +/* + * 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 getXMLPositions() throws Exception { + List xmlPositions = new LinkedList<>(); + for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) { + xmlPositions.add( + new XMLConfiguration( + testConfig.configurationAt(POSITION) + ) + ); + } + return xmlPositions; + } + +} \ No newline at end of file diff --git a/src/test/java/org/hedgecode/chess/ascii/ASCIIParserTest.java b/src/test/java/org/hedgecode/chess/ascii/ASCIIParserTest.java new file mode 100644 index 0000000..87e2698 --- /dev/null +++ b/src/test/java/org/hedgecode/chess/ascii/ASCIIParserTest.java @@ -0,0 +1,74 @@ +/* + * 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 getXMLPositions() throws Exception { + List xmlPositions = new LinkedList<>(); + for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) { + xmlPositions.add( + new XMLConfiguration( + testConfig.configurationAt(POSITION) + ) + ); + } + return xmlPositions; + } + +} \ No newline at end of file diff --git a/src/test/java/org/hedgecode/chess/ascii/ASCIIPositionTest.java b/src/test/java/org/hedgecode/chess/ascii/ASCIIPositionTest.java new file mode 100644 index 0000000..18a52f1 --- /dev/null +++ b/src/test/java/org/hedgecode/chess/ascii/ASCIIPositionTest.java @@ -0,0 +1,37 @@ +/* + * 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 getXMLPositions() throws Exception; + +} diff --git a/src/test/java/org/hedgecode/chess/fen/FENBuilderTest.java b/src/test/java/org/hedgecode/chess/fen/FENBuilderTest.java new file mode 100644 index 0000000..26e2ce8 --- /dev/null +++ b/src/test/java/org/hedgecode/chess/fen/FENBuilderTest.java @@ -0,0 +1,74 @@ +/* + * 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 getXMLPositions() throws Exception { + List xmlPositions = new LinkedList<>(); + for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) { + xmlPositions.add( + new XMLConfiguration( + testConfig.configurationAt(POSITION) + ) + ); + } + return xmlPositions; + } + +} \ No newline at end of file diff --git a/src/test/java/org/hedgecode/chess/fen/FENParserTest.java b/src/test/java/org/hedgecode/chess/fen/FENParserTest.java new file mode 100644 index 0000000..4cb6f87 --- /dev/null +++ b/src/test/java/org/hedgecode/chess/fen/FENParserTest.java @@ -0,0 +1,74 @@ +/* + * 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 getXMLPositions() throws Exception { + List xmlPositions = new LinkedList<>(); + for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) { + xmlPositions.add( + new XMLConfiguration( + testConfig.configurationAt(POSITION) + ) + ); + } + return xmlPositions; + } + +} \ No newline at end of file diff --git a/src/test/java/org/hedgecode/chess/fen/FENPositionTest.java b/src/test/java/org/hedgecode/chess/fen/FENPositionTest.java new file mode 100644 index 0000000..842e26a --- /dev/null +++ b/src/test/java/org/hedgecode/chess/fen/FENPositionTest.java @@ -0,0 +1,35 @@ +/* + * 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 getXMLPositions() throws Exception; + +} diff --git a/src/test/java/org/hedgecode/chess/tcd/TCDBuilderTest.java b/src/test/java/org/hedgecode/chess/tcd/TCDBuilderTest.java new file mode 100644 index 0000000..0818e31 --- /dev/null +++ b/src/test/java/org/hedgecode/chess/tcd/TCDBuilderTest.java @@ -0,0 +1,74 @@ +/* + * 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 getXMLPositions() throws Exception { + List xmlPositions = new LinkedList<>(); + for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) { + xmlPositions.add( + new XMLConfiguration( + testConfig.configurationAt(POSITION) + ) + ); + } + return xmlPositions; + } + +} \ No newline at end of file diff --git a/src/test/java/org/hedgecode/chess/tcd/TCDParserTest.java b/src/test/java/org/hedgecode/chess/tcd/TCDParserTest.java new file mode 100644 index 0000000..6472765 --- /dev/null +++ b/src/test/java/org/hedgecode/chess/tcd/TCDParserTest.java @@ -0,0 +1,74 @@ +/* + * 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 getXMLPositions() throws Exception { + List xmlPositions = new LinkedList<>(); + for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) { + xmlPositions.add( + new XMLConfiguration( + testConfig.configurationAt(POSITION) + ) + ); + } + return xmlPositions; + } + +} \ No newline at end of file diff --git a/src/test/java/org/hedgecode/chess/tcd/TCDPositionTest.java b/src/test/java/org/hedgecode/chess/tcd/TCDPositionTest.java new file mode 100644 index 0000000..33e66d3 --- /dev/null +++ b/src/test/java/org/hedgecode/chess/tcd/TCDPositionTest.java @@ -0,0 +1,36 @@ +/* + * 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 getXMLPositions() throws Exception; + +} diff --git a/src/test/java/org/hedgecode/chess/uci/command/AbstractCommandTest.java b/src/test/java/org/hedgecode/chess/uci/command/AbstractCommandTest.java new file mode 100644 index 0000000..f732337 --- /dev/null +++ b/src/test/java/org/hedgecode/chess/uci/command/AbstractCommandTest.java @@ -0,0 +1,63 @@ +/* + * 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 diff --git a/src/test/java/org/hedgecode/chess/wiki/WikiBuilderTest.java b/src/test/java/org/hedgecode/chess/wiki/WikiBuilderTest.java new file mode 100644 index 0000000..cbb2f2c --- /dev/null +++ b/src/test/java/org/hedgecode/chess/wiki/WikiBuilderTest.java @@ -0,0 +1,99 @@ +/* + * 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 getXMLPositions() throws Exception { + List xmlPositions = new LinkedList<>(); + for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) { + xmlPositions.add( + new XMLConfiguration( + testConfig.configurationAt(POSITION) + ) + ); + } + return xmlPositions; + } + +} \ No newline at end of file diff --git a/src/test/java/org/hedgecode/chess/wiki/WikiParserTest.java b/src/test/java/org/hedgecode/chess/wiki/WikiParserTest.java new file mode 100644 index 0000000..eb397ee --- /dev/null +++ b/src/test/java/org/hedgecode/chess/wiki/WikiParserTest.java @@ -0,0 +1,79 @@ +/* + * 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 getXMLPositions() throws Exception { + List xmlPositions = new LinkedList<>(); + for (HierarchicalConfiguration testConfig : getXMLConfig().configurationsAt(TESTS)) { + xmlPositions.add( + new XMLConfiguration( + testConfig.configurationAt(POSITION) + ) + ); + } + return xmlPositions; + } + +} \ No newline at end of file diff --git a/src/test/java/org/hedgecode/chess/wiki/WikiPositionTest.java b/src/test/java/org/hedgecode/chess/wiki/WikiPositionTest.java new file mode 100644 index 0000000..f298620 --- /dev/null +++ b/src/test/java/org/hedgecode/chess/wiki/WikiPositionTest.java @@ -0,0 +1,36 @@ +/* + * 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 getXMLPositions() throws Exception; + +} diff --git a/src/test/resources/org/hedgecode/chess/ascii/ASCIIBuilderTest.xml b/src/test/resources/org/hedgecode/chess/ascii/ASCIIBuilderTest.xml new file mode 100644 index 0000000..364cc97 --- /dev/null +++ b/src/test/resources/org/hedgecode/chess/ascii/ASCIIBuilderTest.xml @@ -0,0 +1,172 @@ + + + + + + + + Initial Position + + + + HYPHEN + + true + + + + Initial Position + + + + TIGHT + + true + + + + Initial Position + + + + DOT + true + + true + + + + Initial Position + + + + CP866 + false + + true + + + + Reti's Etude + + + + DOT + + + WHITE_KING + WHITE_PAWN + BLACK_KING +
BLACK_PAWN
+
+ WHITE +
+
+ + Empty Position + + + + DOT + + true + WHITE + + +
+
diff --git a/src/test/resources/org/hedgecode/chess/ascii/ASCIIParserTest.xml b/src/test/resources/org/hedgecode/chess/ascii/ASCIIParserTest.xml new file mode 100644 index 0000000..0a84219 --- /dev/null +++ b/src/test/resources/org/hedgecode/chess/ascii/ASCIIParserTest.xml @@ -0,0 +1,186 @@ + + + + + + + + Initial Position + + + + HYPHEN + + true + + + + Initial Position + + + + TIGHT + + true + + + + Initial Position + + + + DOT + true + + true + + + + Initial Position + + + + CP866 + false + + true + + + + Dilaram's Mate + + + + HYPHEN + + + WHITE_KING +

WHITE_ROOK

+

WHITE_ROOK

+

WHITE_BISHOP

+ WHITE_KNIGHT + WHITE_PAWN + WHITE_PAWN + BLACK_KING + BLACK_ROOK + BLACK_ROOK + BLACK_KNIGHT +
+ WHITE +
+
+ + Empty Position + + + + DOT + + true + WHITE + + +
+
diff --git a/src/test/resources/org/hedgecode/chess/fen/FENBuilderTest.xml b/src/test/resources/org/hedgecode/chess/fen/FENBuilderTest.xml new file mode 100644 index 0000000..a68df57 --- /dev/null +++ b/src/test/resources/org/hedgecode/chess/fen/FENBuilderTest.xml @@ -0,0 +1,114 @@ + + + + + + + + Initial Position + rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 + + true + + + + Morphy's Opera Game + 4kb1r/p2n1ppp/4q3/4p1B1/4P3/1Q6/PPP2PPP/2KR4 w k - 0 16 + + + WHITE_KING + WHITE_QUEEN + WHITE_ROOK + WHITE_BISHOP + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN +

WHITE_PAWN

+ BLACK_KING + BLACK_QUEEN + BLACK_ROOK + BLACK_BISHOP + BLACK_KNIGHT + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN +
+ WHITE + + NONE + KING + + 0 + 16 +
+
+ + Immortal Game + r1bk2nr/p2p1pNp/n2B4/1p1NP2P/6P1/3P1Q2/P1P1K3/q5b1 w - - 1 22 + + + WHITE_KING + WHITE_QUEEN + WHITE_BISHOP + WHITE_KNIGHT + WHITE_KNIGHT + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN +
WHITE_PAWN
+ BLACK_KING + BLACK_QUEEN + BLACK_ROOK + BLACK_ROOK + BLACK_BISHOP + BLACK_BISHOP + BLACK_KNIGHT + BLACK_KNIGHT + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN +
+ WHITE + + NONE + NONE + + 1 + 22 +
+
+ + Empty Position + 8/8/8/8/8/8/8/8 w - - 0 1 + + true + WHITE + 0 + 1 + + +
+
diff --git a/src/test/resources/org/hedgecode/chess/fen/FENParserTest.xml b/src/test/resources/org/hedgecode/chess/fen/FENParserTest.xml new file mode 100644 index 0000000..cd6a652 --- /dev/null +++ b/src/test/resources/org/hedgecode/chess/fen/FENParserTest.xml @@ -0,0 +1,117 @@ + + + + + + + + Initial Position + rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1 + + true + + + + Evergreen Game + 1r2k1r1/pbppnp1p/1b3P2/8/Q7/B1PB1q2/P4PPP/3R2K1 w - - 0 21 + + + WHITE_KING + WHITE_QUEEN + WHITE_ROOK + WHITE_BISHOP + WHITE_BISHOP + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN +

WHITE_PAWN

+ BLACK_KING + BLACK_QUEEN + BLACK_ROOK + BLACK_ROOK + BLACK_BISHOP + BLACK_BISHOP + BLACK_KNIGHT + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN +
+ WHITE + + NONE + NONE + + 0 + 21 +
+
+ + Immortal Zugzwang Game + 6k1/3q2p1/p2bp2p/3p1r2/1p1Pp3/3bQ1PP/PP1B1rB1/1N2R1RK w - - 0 26 + + +

WHITE_KING

+ WHITE_QUEEN + WHITE_ROOK + WHITE_ROOK + WHITE_BISHOP + WHITE_BISHOP + WHITE_KNIGHT + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN +

WHITE_PAWN

+ BLACK_KING + BLACK_QUEEN + BLACK_ROOK + BLACK_ROOK + BLACK_BISHOP + BLACK_BISHOP + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN +
BLACK_PAWN
+
+ WHITE + + NONE + NONE + + 0 + 26 +
+
+ + Empty Position + 8/8/8/8/8/8/8/8 w - - 0 1 + + true + WHITE + 0 + 1 + + +
+
diff --git a/src/test/resources/org/hedgecode/chess/tcd/TCDBuilderTest.xml b/src/test/resources/org/hedgecode/chess/tcd/TCDBuilderTest.xml new file mode 100644 index 0000000..07a0713 --- /dev/null +++ b/src/test/resources/org/hedgecode/chess/tcd/TCDBuilderTest.xml @@ -0,0 +1,125 @@ + + + + + + + + Initial Position + xG + + true + + + + Morphy's Opera Game + AwNMIHJL1FdCEAVBGLvF+dnP4Xo6-hepgGH0yP0XP + + + WHITE_KING + WHITE_QUEEN + WHITE_ROOK + WHITE_BISHOP + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN +

WHITE_PAWN

+ BLACK_KING + BLACK_QUEEN + BLACK_ROOK + BLACK_BISHOP + BLACK_KNIGHT + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN +
+ WHITE + + NONE + KING + + 0 + 16 +
+
+ + Immortal Game + + + + WHITE_KING + WHITE_QUEEN + WHITE_BISHOP + WHITE_KNIGHT + WHITE_KNIGHT + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN +
WHITE_PAWN
+ BLACK_KING + BLACK_QUEEN + BLACK_ROOK + BLACK_ROOK + BLACK_BISHOP + BLACK_BISHOP + BLACK_KNIGHT + BLACK_KNIGHT + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN +
+ WHITE + + NONE + NONE + + 1 + 22 +
+
+ + Reti's Etude + + true + + + WHITE_KING + WHITE_PAWN + BLACK_KING +
BLACK_PAWN
+
+
+
+ + Empty Position + GG + true + + true + + +
+
diff --git a/src/test/resources/org/hedgecode/chess/tcd/TCDParserTest.xml b/src/test/resources/org/hedgecode/chess/tcd/TCDParserTest.xml new file mode 100644 index 0000000..59f5133 --- /dev/null +++ b/src/test/resources/org/hedgecode/chess/tcd/TCDParserTest.xml @@ -0,0 +1,130 @@ + + + + + + + + Initial Position + xG + + true + + + + Evergreen Game + AoJVMHMkKPTCE04FGLFV+4nPfYMNawOhjpgGH0xP0XU + + + WHITE_KING + WHITE_QUEEN + WHITE_ROOK + WHITE_BISHOP + WHITE_BISHOP + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN +

WHITE_PAWN

+ BLACK_KING + BLACK_QUEEN + BLACK_ROOK + BLACK_ROOK + BLACK_BISHOP + BLACK_BISHOP + BLACK_KNIGHT + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN +
+ WHITE + + NONE + NONE + + 0 + 21 +
+
+ + Immortal Zugzwang Game + AfSYHORACKNLLFEDVGGNvE9K2ecYZ3alih4pwGH0xP0XZ + + +

WHITE_KING

+ WHITE_QUEEN + WHITE_ROOK + WHITE_ROOK + WHITE_BISHOP + WHITE_BISHOP + WHITE_KNIGHT + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN + WHITE_PAWN +

WHITE_PAWN

+ BLACK_KING + BLACK_QUEEN + BLACK_ROOK + BLACK_ROOK + BLACK_BISHOP + BLACK_BISHOP + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN + BLACK_PAWN +
BLACK_PAWN
+
+ WHITE + + NONE + NONE + + 0 + 26 +
+
+ + Reti's Etude Variation + ABnGgJv9mpEG + true + + +
WHITE_KING
+ WHITE_PAWN + BLACK_KING + BLACK_PAWN + BLACK_PAWN +
BLACK_PAWN
+
+
+
+ + Empty Position + GG + true + + true + + +
+
diff --git a/src/test/resources/org/hedgecode/chess/wiki/WikiBuilderTest.xml b/src/test/resources/org/hedgecode/chess/wiki/WikiBuilderTest.xml new file mode 100644 index 0000000..065d2a9 --- /dev/null +++ b/src/test/resources/org/hedgecode/chess/wiki/WikiBuilderTest.xml @@ -0,0 +1,92 @@ + + + + + + + + Initial Position + + + + true + + true + + + + Reti's Etude Variation + + + + false + + +
WHITE_KING
+ WHITE_PAWN + BLACK_KING + BLACK_PAWN + BLACK_PAWN +
BLACK_PAWN
+
+ WHITE +
+
+ + Empty Position + + + + + true + WHITE + + +
+
diff --git a/src/test/resources/org/hedgecode/chess/wiki/WikiParserTest.xml b/src/test/resources/org/hedgecode/chess/wiki/WikiParserTest.xml new file mode 100644 index 0000000..3cdcd7e --- /dev/null +++ b/src/test/resources/org/hedgecode/chess/wiki/WikiParserTest.xml @@ -0,0 +1,89 @@ + + + + + + + + Initial Position + + + + false + + true + + + + Anderssen's Mate + + + + false + + + WHITE_KING + WHITE_BISHOP + WHITE_BISHOP + WHITE_PAWN +

WHITE_PAWN

+
BLACK_KING
+ BLACK_PAWN +

BLACK_PAWN

+
+ WHITE +
+
+ + Empty Position + + + + + true + WHITE + + +
+