[LIB-9] Add functional for build image chess diagrams
[chesshog.git] / chesshog-db-etude / src / main / java / org / hedgecode / chess / EtudeUtils.java
1 /*
2  * Copyright (c) 2018. Developed by Hedgecode.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.hedgecode.chess;
18
19 import java.math.BigInteger;
20 import java.util.Arrays;
21 import java.util.HashMap;
22 import java.util.Map;
23
24 import org.hedgecode.chess.position.Color;
25 import org.hedgecode.chess.position.ColorPiece;
26 import org.hedgecode.chess.position.Piece;
27 import org.hedgecode.chess.position.Position;
28 import org.hedgecode.chess.position.Positions;
29 import org.hedgecode.chess.position.Square;
30 import org.hedgecode.chess.position.SquareSort;
31
32 /**
33  *
34  *
35  * @author Dmitry Samoshin aka gotty
36  */
37 public final class EtudeUtils {
38
39     private static final byte PIECE_MASK   = 0b1111;
40     private static final byte PIECE_LENGTH = 4;
41
42     private static final byte NUM_WHITE_PAWN   = 0;
43     private static final byte NUM_WHITE_KNIGHT = 1;
44     private static final byte NUM_WHITE_BISHOP = 2;
45     private static final byte NUM_WHITE_ROOK   = 3;
46     private static final byte NUM_WHITE_QUEEN  = 4;
47
48     private static final byte NUM_BLACK_PAWN   = 5;
49     private static final byte NUM_BLACK_KNIGHT = 6;
50     private static final byte NUM_BLACK_BISHOP = 7;
51     private static final byte NUM_BLACK_ROOK   = 8;
52     private static final byte NUM_BLACK_QUEEN  = 9;
53
54     private static final byte BLOB_PIECE_EMPTY  = 0b0000;
55
56     private static final byte BLOB_WHITE_PAWN   = 0b0001;
57     private static final byte BLOB_WHITE_KNIGHT = 0b0010;
58     private static final byte BLOB_WHITE_BISHOP = 0b0011;
59     private static final byte BLOB_WHITE_ROOK   = 0b0100;
60     private static final byte BLOB_WHITE_QUEEN  = 0b0101;
61     private static final byte BLOB_WHITE_KING   = 0b0110;
62
63     private static final byte BLOB_BLACK_PAWN   = 0b1001;
64     private static final byte BLOB_BLACK_KNIGHT = 0b1010;
65     private static final byte BLOB_BLACK_BISHOP = 0b1011;
66     private static final byte BLOB_BLACK_ROOK   = 0b1100;
67     private static final byte BLOB_BLACK_QUEEN  = 0b1101;
68     private static final byte BLOB_BLACK_KING   = 0b1110;
69
70     private static final Map<ColorPiece, Byte> PIECE_NUMBERS = new HashMap<ColorPiece, Byte>() {
71         {
72             put(ColorPiece.WHITE_PAWN, NUM_WHITE_PAWN);     put(ColorPiece.BLACK_PAWN, NUM_BLACK_PAWN);
73             put(ColorPiece.WHITE_KNIGHT, NUM_WHITE_KNIGHT); put(ColorPiece.BLACK_KNIGHT, NUM_BLACK_KNIGHT);
74             put(ColorPiece.WHITE_BISHOP, NUM_WHITE_BISHOP); put(ColorPiece.BLACK_BISHOP, NUM_BLACK_BISHOP);
75             put(ColorPiece.WHITE_ROOK, NUM_WHITE_ROOK);     put(ColorPiece.BLACK_ROOK, NUM_BLACK_ROOK);
76             put(ColorPiece.WHITE_QUEEN, NUM_WHITE_QUEEN);   put(ColorPiece.BLACK_QUEEN, NUM_BLACK_QUEEN);
77         }
78     };
79
80     private static final Map<ColorPiece, Byte> BLOB_PIECES = new HashMap<ColorPiece, Byte>() {
81         {
82             put(ColorPiece.WHITE_PAWN, BLOB_WHITE_PAWN);     put(ColorPiece.BLACK_PAWN, BLOB_BLACK_PAWN);
83             put(ColorPiece.WHITE_KNIGHT, BLOB_WHITE_KNIGHT); put(ColorPiece.BLACK_KNIGHT, BLOB_BLACK_KNIGHT);
84             put(ColorPiece.WHITE_BISHOP, BLOB_WHITE_BISHOP); put(ColorPiece.BLACK_BISHOP, BLOB_BLACK_BISHOP);
85             put(ColorPiece.WHITE_ROOK, BLOB_WHITE_ROOK);     put(ColorPiece.BLACK_ROOK, BLOB_BLACK_ROOK);
86             put(ColorPiece.WHITE_QUEEN, BLOB_WHITE_QUEEN);   put(ColorPiece.BLACK_QUEEN, BLOB_BLACK_QUEEN);
87             put(ColorPiece.WHITE_KING, BLOB_WHITE_KING);     put(ColorPiece.BLACK_KING, BLOB_BLACK_KING);
88         }
89     };
90
91     public static BigInteger hashPosition(Position position) {
92         StringBuilder sb = new StringBuilder();
93         sb.append(
94                 numSquare(
95                         kingSquare(Color.WHITE, position)
96                 )
97         ).append(
98                 numSquare(
99                         kingSquare(Color.BLACK, position)
100                 )
101         );
102         int empty = 0;
103         for (Map.Entry<Square, ColorPiece> entry : position.getSquares(SquareSort.A8H1).entrySet()) {
104             ColorPiece colorPiece = entry.getValue();
105             if (colorPiece != null && !Piece.KING.equals(colorPiece.piece())) {
106                 if (empty > 0)
107                     sb.append(empty);
108                 sb.append(
109                         PIECE_NUMBERS.get(colorPiece)
110                 );
111                 empty = 0;
112             } else {
113                 ++empty;
114             }
115         }
116         if (empty > 0)
117             sb.append(empty);
118
119         return new BigInteger(
120                 sb.toString() /* todo: SQL: NUMERIC(64,0) */
121         );
122     }
123
124     public static byte[] blobPosition(Position position) {
125         byte[] blob = new byte[Square.getSize() * Square.getSize()];
126         int i = 0;
127         for (Map.Entry<Square, ColorPiece> entry : position.getSquares(SquareSort.A8H1).entrySet()) {
128             ColorPiece colorPiece = entry.getValue();
129             blob[i++] = colorPiece != null ? BLOB_PIECES.get(colorPiece) : BLOB_PIECE_EMPTY;
130         }
131         return compress(blob);
132     }
133
134     private static Square kingSquare(Color color, Position position) {
135         Square kingSquare = null;
136
137         Map<Square, ColorPiece> king = position.getSquarePieces(color, Piece.KING);
138
139         if (king.isEmpty() || king.size() > 1)
140             throw new RuntimeException("Incorrect position"); // todo
141
142         for (Square square : king.keySet()) {
143             kingSquare = square;
144         }
145         return kingSquare;
146     }
147
148     private static int numSquare(Square square) {
149         int v = square.getV() + 1;
150         int h = Square.getSize() - square.getH();
151         return Square.getSize() * (h - 1) + v;
152     }
153
154     private static byte[] compress(byte[] bytes) {
155         byte[] cmpBytes = new byte[bytes.length / 2];
156         byte high, low;
157         int i = 0;
158         for (int j = 0; j < cmpBytes.length; ++j) {
159             high = (byte) ((bytes[i++] & PIECE_MASK) << PIECE_LENGTH);
160             low  = (byte) (bytes[i++] & PIECE_MASK);
161             cmpBytes[j] = (byte) (high | low);
162         }
163         return cmpBytes;
164     }
165
166     private EtudeUtils() {
167         throw new AssertionError(
168                 "No org.hedgecode.chess.EtudeUtils instances!"
169         );
170     }
171
172
173     public static void main(String... args) {
174         System.out.println(
175                 hashPosition(Positions.INITIAL.getPosition())
176         );
177         System.out.println(
178                 Arrays.toString(blobPosition(Positions.INITIAL.getPosition()))
179         );
180     }
181
182 }