/* * 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 PIECE_NUMBERS = new HashMap() { { 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 BLOB_PIECES = new HashMap() { { 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 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 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 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())) ); } }