[LIB-9] Rename chesshog-dbetude module
[chesshog.git] / chesshog-dbetude / src / main / java / org / hedgecode / chess / EtudeUtils.java
diff --git a/chesshog-dbetude/src/main/java/org/hedgecode/chess/EtudeUtils.java b/chesshog-dbetude/src/main/java/org/hedgecode/chess/EtudeUtils.java
new file mode 100644 (file)
index 0000000..268ca54
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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.math.BigInteger;
+import java.util.Arrays;
+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;
+import org.hedgecode.chess.position.Position;
+import org.hedgecode.chess.position.Positions;
+import org.hedgecode.chess.position.Square;
+import org.hedgecode.chess.position.SquareSort;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class EtudeUtils {
+
+    private static final byte PIECE_MASK   = 0b1111;
+    private static final byte PIECE_LENGTH = 4;
+
+    private static final byte NUM_WHITE_PAWN   = 0;
+    private static final byte NUM_WHITE_KNIGHT = 1;
+    private static final byte NUM_WHITE_BISHOP = 2;
+    private static final byte NUM_WHITE_ROOK   = 3;
+    private static final byte NUM_WHITE_QUEEN  = 4;
+
+    private static final byte NUM_BLACK_PAWN   = 5;
+    private static final byte NUM_BLACK_KNIGHT = 6;
+    private static final byte NUM_BLACK_BISHOP = 7;
+    private static final byte NUM_BLACK_ROOK   = 8;
+    private static final byte NUM_BLACK_QUEEN  = 9;
+
+    private static final byte BLOB_PIECE_EMPTY  = 0b0000;
+
+    private static final byte BLOB_WHITE_PAWN   = 0b0001;
+    private static final byte BLOB_WHITE_KNIGHT = 0b0010;
+    private static final byte BLOB_WHITE_BISHOP = 0b0011;
+    private static final byte BLOB_WHITE_ROOK   = 0b0100;
+    private static final byte BLOB_WHITE_QUEEN  = 0b0101;
+    private static final byte BLOB_WHITE_KING   = 0b0110;
+
+    private static final byte BLOB_BLACK_PAWN   = 0b1001;
+    private static final byte BLOB_BLACK_KNIGHT = 0b1010;
+    private static final byte BLOB_BLACK_BISHOP = 0b1011;
+    private static final byte BLOB_BLACK_ROOK   = 0b1100;
+    private static final byte BLOB_BLACK_QUEEN  = 0b1101;
+    private static final byte BLOB_BLACK_KING   = 0b1110;
+
+    private static final Map<ColorPiece, Byte> PIECE_NUMBERS = new HashMap<ColorPiece, Byte>() {
+        {
+            put(ColorPiece.WHITE_PAWN, NUM_WHITE_PAWN);     put(ColorPiece.BLACK_PAWN, NUM_BLACK_PAWN);
+            put(ColorPiece.WHITE_KNIGHT, NUM_WHITE_KNIGHT); put(ColorPiece.BLACK_KNIGHT, NUM_BLACK_KNIGHT);
+            put(ColorPiece.WHITE_BISHOP, NUM_WHITE_BISHOP); put(ColorPiece.BLACK_BISHOP, NUM_BLACK_BISHOP);
+            put(ColorPiece.WHITE_ROOK, NUM_WHITE_ROOK);     put(ColorPiece.BLACK_ROOK, NUM_BLACK_ROOK);
+            put(ColorPiece.WHITE_QUEEN, NUM_WHITE_QUEEN);   put(ColorPiece.BLACK_QUEEN, NUM_BLACK_QUEEN);
+        }
+    };
+
+    private static final Map<ColorPiece, Byte> BLOB_PIECES = new HashMap<ColorPiece, Byte>() {
+        {
+            put(ColorPiece.WHITE_PAWN, BLOB_WHITE_PAWN);     put(ColorPiece.BLACK_PAWN, BLOB_BLACK_PAWN);
+            put(ColorPiece.WHITE_KNIGHT, BLOB_WHITE_KNIGHT); put(ColorPiece.BLACK_KNIGHT, BLOB_BLACK_KNIGHT);
+            put(ColorPiece.WHITE_BISHOP, BLOB_WHITE_BISHOP); put(ColorPiece.BLACK_BISHOP, BLOB_BLACK_BISHOP);
+            put(ColorPiece.WHITE_ROOK, BLOB_WHITE_ROOK);     put(ColorPiece.BLACK_ROOK, BLOB_BLACK_ROOK);
+            put(ColorPiece.WHITE_QUEEN, BLOB_WHITE_QUEEN);   put(ColorPiece.BLACK_QUEEN, BLOB_BLACK_QUEEN);
+            put(ColorPiece.WHITE_KING, BLOB_WHITE_KING);     put(ColorPiece.BLACK_KING, BLOB_BLACK_KING);
+        }
+    };
+
+    public static BigInteger hashPosition(Position position) {
+        StringBuilder sb = new StringBuilder();
+        sb.append(
+                numSquare(
+                        kingSquare(Color.WHITE, position)
+                )
+        ).append(
+                numSquare(
+                        kingSquare(Color.BLACK, position)
+                )
+        );
+        int empty = 0;
+        for (Map.Entry<Square, ColorPiece> entry : position.getSquares(SquareSort.A8H1).entrySet()) {
+            ColorPiece colorPiece = entry.getValue();
+            if (colorPiece != null && !Piece.KING.equals(colorPiece.piece())) {
+                if (empty > 0)
+                    sb.append(empty);
+                sb.append(
+                        PIECE_NUMBERS.get(colorPiece)
+                );
+                empty = 0;
+            } else {
+                ++empty;
+            }
+        }
+        if (empty > 0)
+            sb.append(empty);
+
+        return new BigInteger(
+                sb.toString() /* todo: SQL: NUMERIC(64,0) */
+        );
+    }
+
+    public static byte[] blobPosition(Position position) {
+        byte[] blob = new byte[Square.getSize() * Square.getSize()];
+        int i = 0;
+        for (Map.Entry<Square, ColorPiece> entry : position.getSquares(SquareSort.A8H1).entrySet()) {
+            ColorPiece colorPiece = entry.getValue();
+            blob[i++] = colorPiece != null ? BLOB_PIECES.get(colorPiece) : BLOB_PIECE_EMPTY;
+        }
+        return compress(blob);
+    }
+
+    private static Square kingSquare(Color color, Position position) {
+        Square kingSquare = null;
+
+        Map<Square, ColorPiece> king = position.getSquarePieces(color, Piece.KING);
+
+        if (king.isEmpty() || king.size() > 1)
+            throw new RuntimeException("Incorrect position"); // todo
+
+        for (Square square : king.keySet()) {
+            kingSquare = square;
+        }
+        return kingSquare;
+    }
+
+    private static int numSquare(Square square) {
+        int v = square.getV() + 1;
+        int h = Square.getSize() - square.getH();
+        return Square.getSize() * (h - 1) + v;
+    }
+
+    private static 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++] & PIECE_MASK) << PIECE_LENGTH);
+            low  = (byte) (bytes[i++] & PIECE_MASK);
+            cmpBytes[j] = (byte) (high | low);
+        }
+        return cmpBytes;
+    }
+
+    private EtudeUtils() {
+        throw new AssertionError(
+                "No org.hedgecode.chess.EtudeUtils instances!"
+        );
+    }
+
+
+    public static void main(String... args) {
+        System.out.println(
+                hashPosition(Positions.INITIAL.getPosition())
+        );
+        System.out.println(
+                Arrays.toString(blobPosition(Positions.INITIAL.getPosition()))
+        );
+    }
+
+}