--- /dev/null
+/*
+ * Copyright (c) 2019-2020. 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.scanner.format;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * AbstractPGNFormat
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public abstract class AbstractPGNFormat implements PGNFormat {
+
+ private static final String MOVES_FORMAT = "%s %s";
+
+ private final DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd");
+ private final DateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
+
+ private final Map<PGNTag, String> pgnTags = new HashMap<>();
+
+ private String pgnMoves;
+
+ @Override
+ public void addTag(PGNTag tag, String value) {
+ pgnTags.put(tag, value);
+ }
+
+ public String getTag(PGNTag tag) {
+ return pgnTags.get(tag);
+ }
+
+ @Override
+ public void addMoves(String moves) {
+ pgnMoves = moves;
+ }
+
+ @Override
+ public String formatDate(Date date) {
+ return dateFormat.format(date);
+ }
+
+ @Override
+ public String formatTime(Date time) {
+ return timeFormat.format(time);
+ }
+
+ protected String formatMoves() {
+ return String.format(
+ MOVES_FORMAT, moves(), result()
+ );
+ }
+
+ protected String formatTagValue(String value) {
+ return value.replaceAll("([\\\\\"])", "\\\\$1");
+ }
+
+ private String moves() {
+ return pgnMoves != null ? pgnMoves : PGNTag.EMPTY;
+ }
+
+ private String result() {
+ String result = pgnTags.get(PGNTag.RESULT);
+ return result != null ? result : PGNTag.RESULT.defaultValue();
+ }
+
+}
Move[] moves();
- String formatMoves();
-
}
*
* @author Dmitry Samoshin aka gotty
*/
-public interface Move {
+public interface Move extends Comparable<Move> {
- int number();
+ int ply();
String move();
+ @Override
+ default int compareTo(Move move) {
+ return this.ply() - move.ply();
+ }
+
}
--- /dev/null
+/*
+ * Copyright (c) 2019-2020. 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.scanner.format;
+
+/**
+ * MovesFormat
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface MovesFormat {
+
+ String format(Move[] moves);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2019-2020. 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.scanner.format;
+
+/**
+ * PGNConstants
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class PGNConstants {
+
+ public static final int PGN_DEF_LINE_LENGTH = 80;
+ public static final int PGN_MAX_LINE_LENGTH = 255;
+
+ public static final String PGN_CRLF = "\n";
+
+ public static final String WHITE_MOVE_FORMAT = "%d. %s ";
+ public static final String BLACK_MOVE_FORMAT = "%s ";
+
+
+ private PGNConstants() {
+ throw new AssertionError(
+ String.format("No %s instances!", getClass().getName())
+ );
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2019-2020. 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.scanner.format;
+
+import java.util.Date;
+
+/**
+ * PGNFormat
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface PGNFormat {
+
+ void addTag(PGNTag tag, String value);
+
+ void addMoves(String moves);
+
+ String format();
+
+ String formatDate(Date date);
+
+ String formatTime(Date time);
+
+}
* limitations under the License.
*/
-package org.hedgecode.chess.scanner.entity;
+package org.hedgecode.chess.scanner.format;
+
+import java.util.Arrays;
+import java.util.Comparator;
/**
* PGNTag
EVENT ( "Event", true, PGNTag.QUESTION ),
SITE ( "Site", true, PGNTag.QUESTION ),
DATE ( "Date", true, PGNTag.QUESTION_DATE ),
- TIME ( "Time", false, PGNTag.QUESTION_TIME ),
ROUND ( "Round", true, PGNTag.QUESTION ),
WHITE ( "White", true, PGNTag.QUESTION ),
BLACK ( "Black", true, PGNTag.QUESTION ),
+ RESULT ( "Result", true, PGNTag.NON_RESULT ),
WHITE_TITLE ( "WhiteTitle", false, PGNTag.HYPHEN ),
BLACK_TITLE ( "BlackTitle", false, PGNTag.HYPHEN ),
WHITE_ELO ( "WhiteElo", false, PGNTag.HYPHEN ),
SUBVARIATION ( "SubVariation", false, PGNTag.EMPTY ),
ECO ( "ECO", false, PGNTag.EMPTY ),
NIC ( "NIC", false, PGNTag.EMPTY ),
- UTC_DATE ( "UTCDate", false, PGNTag.QUESTION_DATE ),
+ TIME ( "Time", false, PGNTag.QUESTION_TIME ),
UTC_TIME ( "UTCTime", false, PGNTag.QUESTION_TIME ),
+ UTC_DATE ( "UTCDate", false, PGNTag.QUESTION_DATE ),
TIME_CONTROL ( "TimeControl", false, PGNTag.QUESTION ),
SETUP ( "SetUp", false, PGNTag.ZERO ),
FEN ( "FEN", false, PGNTag.EMPTY ),
TERMINATION ( "Termination", false, PGNTag.EMPTY ),
ANNOTATOR ( "Annotator", false, PGNTag.EMPTY ),
MODE ( "Mode", false, PGNTag.EMPTY ),
- PLY_COUNT ( "PlyCount", false, PGNTag.EMPTY ),
- RESULT ( "Result", true, PGNTag.NON_RESULT );
+ PLY_COUNT ( "PlyCount", false, PGNTag.EMPTY );
public static final String EMPTY = "";
public static final String HYPHEN = "-";
return defaultValue;
}
+ public static PGNTag[] tags() {
+ PGNTag[] tags = values();
+ Arrays.sort(
+ tags, new TagComparator()
+ );
+ return tags;
+ }
+
+ static class TagComparator implements Comparator<PGNTag> {
+
+ @Override
+ public int compare(PGNTag tag1, PGNTag tag2) {
+ if (tag1.isRequired && tag2.isRequired) {
+ return tag1.ordinal() - tag2.ordinal();
+ } else {
+ return tag1.isRequired ? -1
+ : tag2.isRequired ? 1
+ : tag1.name().compareTo(tag2.name());
+ }
+ }
+
+ }
+
}
--- /dev/null
+/*
+ * Copyright (c) 2019-2020. 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.scanner.format;
+
+import static org.hedgecode.chess.scanner.format.PGNConstants.*;
+
+/**
+ * ReducePGNFormat
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class ReducePGNFormat extends AbstractPGNFormat {
+
+ @Override
+ public String format() {
+ StringBuilder sb = new StringBuilder();
+ for (PGNTag tag : PGNTag.tags()) {
+ String tagValue = getTag(tag);
+ if (tag.isRequired() || tagValue != null) {
+ sb.append(
+ String.format(
+ PGNTag.TAG_FORMAT,
+ tag.getName(),
+ tagValue != null ? formatTagValue(tagValue) : tag.defaultValue()
+ )
+ ).append(PGN_CRLF);
+ }
+ }
+ sb.append(PGN_CRLF).append(
+ formatMoves()
+ ).append(PGN_CRLF);
+ return sb.toString();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2019-2020. 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.scanner.format;
+
+import java.util.Arrays;
+
+import static org.hedgecode.chess.scanner.format.PGNConstants.*;
+
+/**
+ * TypeMovesFormat
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum TypeMovesFormat {
+
+ LINE ( new LineMovesFormat() ),
+ WRAP ( new WrapMovesFormat() );
+
+ private MovesFormat movesFormat;
+
+ TypeMovesFormat(MovesFormat movesFormat) {
+ this.movesFormat = movesFormat;
+ }
+
+ public String format(Move[] moves) {
+ return movesFormat.format(moves);
+ }
+
+ static class LineMovesFormat extends WrapMovesFormat {
+
+ LineMovesFormat() {
+ super(PGN_MAX_LINE_LENGTH);
+ }
+
+ }
+
+ static class WrapMovesFormat implements MovesFormat {
+
+ private int lineLength;
+
+ WrapMovesFormat() {
+ this(PGN_DEF_LINE_LENGTH);
+ }
+
+ WrapMovesFormat(int length) {
+ lineLength = length;
+ }
+
+ @Override
+ public String format(Move[] moves) {
+ Arrays.sort(moves);
+ int maxLength = lineLength - PGN_CRLF.length();
+ int length = 0;
+ StringBuilder sb = new StringBuilder();
+ for (Move move : moves) {
+ String nextMove = move.ply() % 2 != 0
+ ? String.format(WHITE_MOVE_FORMAT, move.ply() / 2 + 1, move.move())
+ : String.format(BLACK_MOVE_FORMAT, move.move());
+ if (length + nextMove.length() > maxLength) {
+ sb.append(PGN_CRLF);
+ length = 0;
+ }
+ sb.append(nextMove);
+ length += nextMove.length();
+ }
+ return sb.toString().trim();
+ }
+
+ }
+
+}
+++ /dev/null
-/*
- * Copyright (c) 2019-2020. 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.scanner.json.format;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.hedgecode.chess.scanner.entity.PGNEntity;
-import org.hedgecode.chess.scanner.entity.PGNTag;
-
-import static org.hedgecode.chess.scanner.ChessHogScannerConstants.*;
-
-/**
- * AbstractPGNFormat
- *
- * @author Dmitry Samoshin aka gotty
- */
-public abstract class AbstractPGNFormat extends AbstractBaseFormat implements PGNEntity {
-
- private static final String EMPTY = "";
-
- private static final String MOVES_FORMAT = "%s %s";
-
- private final Map<PGNTag, String> pgnTags = new HashMap<>();
- private String pgnMoves;
-
- protected abstract void assignPGN();
-
- protected void addTag(PGNTag tag, String value) {
- pgnTags.put(tag, value);
- }
-
- protected void addMoves(String moves) {
- pgnMoves = moves;
- }
-
- private String moves() {
- return pgnMoves != null ? pgnMoves : EMPTY;
- }
-
- private String result() {
- String result = pgnTags.get(PGNTag.RESULT);
- return result != null ? result : PGNTag.RESULT.defaultValue();
- }
-
- @Override
- public String pgn() {
- assignPGN();
- StringBuilder sb = new StringBuilder();
- for (PGNTag tag : PGNTag.values()) {
- String tagValue = pgnTags.get(tag);
- if (tag.isRequired() || tagValue != null) {
- sb.append(
- String.format(
- PGNTag.TAG_FORMAT,
- tag.getName(),
- tagValue != null ? tagValue : tag.defaultValue()
- )
- ).append(CRLF);
- }
- }
- sb.append(CRLF).append(
- String.format(MOVES_FORMAT, moves(), result())
- ).append(CRLF);
- return sb.toString();
- }
-
-}
*/
public class JSONGameData implements GameData {
- private static final String WHITE_MOVE_FORMAT = "%d. %s ";
- private static final String BLACK_MOVE_FORMAT = "%s ";
-
@SerializedName("game")
private JSONGame game;
return moves;
}
- @Override
- public String formatMoves() {
- StringBuilder sb = new StringBuilder();
- for (Move move : moves) {
- if (move.number() % 2 == 0) {
- sb.append(
- String.format(WHITE_MOVE_FORMAT, move.number() / 2 + 1, move.move())
- );
- } else {
- sb.append(
- String.format(BLACK_MOVE_FORMAT, move.move())
- );
- }
- }
- return sb.toString();
- }
-
}
package org.hedgecode.chess.scanner.json.format;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-
import com.google.gson.annotations.SerializedName;
-import org.hedgecode.chess.scanner.entity.PGNTag;
+import org.hedgecode.chess.scanner.format.PGNFormat;
+import org.hedgecode.chess.scanner.format.PGNTag;
import org.hedgecode.chess.scanner.format.GameData;
import org.hedgecode.chess.scanner.format.GameFormat;
+import org.hedgecode.chess.scanner.format.TypeMovesFormat;
+import org.hedgecode.chess.scanner.spi.ServiceRegistry;
/**
* JSONGameFormat
*
* @author Dmitry Samoshin aka gotty
*/
-public class JSONGameFormat extends AbstractPGNFormat implements GameFormat {
-
- private final DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd");
- private final DateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
+public class JSONGameFormat extends AbstractBaseFormat implements GameFormat {
@SerializedName("gameData")
private JSONGameData gameData;
return gameData;
}
+
@Override
- protected void assignPGN() {
- addTag(PGNTag.EVENT, gameData.room().name());
- addTag(PGNTag.DATE, dateFormat.format(gameData.game().startAt()));
- addTag(PGNTag.TIME, timeFormat.format(gameData.game().startAt()));
- addTag(PGNTag.ROUND, gameData.game().roundSlug());
- addTag(PGNTag.WHITE, gameData.game().white().name());
- addTag(PGNTag.BLACK, gameData.game().black().name());
- addTag(PGNTag.WHITE_TITLE, gameData.game().white().title());
- addTag(PGNTag.BLACK_TITLE, gameData.game().black().title());
- addTag(PGNTag.WHITE_ELO, Integer.toString(gameData.game().whiteElo()));
- addTag(PGNTag.BLACK_ELO, Integer.toString(gameData.game().blackElo()));
- addTag(PGNTag.EVENT_DATE, dateFormat.format(gameData.room().startAt()));
- addTag(PGNTag.RESULT, gameData.game().result());
+ public String pgn() {
+ PGNFormat pgnFormat = ServiceRegistry.singleProvider(
+ PGNFormat.class
+ );
+ pgnFormat.addTag(PGNTag.EVENT, gameData.room().name());
+ pgnFormat.addTag(PGNTag.DATE, pgnFormat.formatDate(gameData.game().startAt()));
+ pgnFormat.addTag(PGNTag.ROUND, gameData.game().roundSlug());
+ pgnFormat.addTag(PGNTag.WHITE, gameData.game().white().name());
+ pgnFormat.addTag(PGNTag.BLACK, gameData.game().black().name());
+ pgnFormat.addTag(PGNTag.WHITE_TITLE, gameData.game().white().title());
+ pgnFormat.addTag(PGNTag.BLACK_TITLE, gameData.game().black().title());
+ pgnFormat.addTag(PGNTag.WHITE_ELO, Integer.toString(gameData.game().whiteElo()));
+ pgnFormat.addTag(PGNTag.BLACK_ELO, Integer.toString(gameData.game().blackElo()));
+ pgnFormat.addTag(PGNTag.EVENT_DATE, pgnFormat.formatDate(gameData.room().startAt()));
+ pgnFormat.addTag(PGNTag.TIME, pgnFormat.formatTime(gameData.game().startAt()));
+ pgnFormat.addTag(PGNTag.RESULT, gameData.game().result());
if (gameData.moves().length > 0) {
- addTag(PGNTag.PLY_COUNT, Integer.toString(gameData.moves().length));
+ pgnFormat.addTag(PGNTag.PLY_COUNT, Integer.toString(gameData.moves().length));
}
-
- addMoves(gameData.formatMoves());
+ pgnFormat.addMoves(
+ TypeMovesFormat.WRAP.format(gameData.moves())
+ );
+ return pgnFormat.format();
}
}
}
@Override
- public int number() {
- return ply;
+ public int ply() {
+ return ply + 1;
}
@Override
--- /dev/null
+org.hedgecode.chess.scanner.format.ReducePGNFormat
\ No newline at end of file