2 * Copyright (c) 2018. Developed by Hedgecode.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.hedgecode.chess.tcd;
21 import org.hedgecode.chess.Builders;
22 import org.hedgecode.chess.Parsers;
23 import org.hedgecode.chess.position.Builder;
24 import org.hedgecode.chess.position.Castle;
25 import org.hedgecode.chess.position.Color;
26 import org.hedgecode.chess.position.ColorPiece;
27 import org.hedgecode.chess.position.ParseException;
28 import org.hedgecode.chess.position.Piece;
29 import org.hedgecode.chess.position.Position;
30 import org.hedgecode.chess.position.Positions;
31 import org.hedgecode.chess.position.Square;
34 * Tiny Chess Diagram (TCD) builder.
36 * @author Dmitry Samoshin aka gotty
38 public final class TCDBuilder implements Builder {
40 private static final byte[] EMPTY = {};
42 private static Builder _instance = new TCDBuilder();
44 private TCDBuilder() {
48 public String build(Position position) {
54 private String _build(Position position) {
56 byte[] white = _buildColor(Color.WHITE, position);
57 byte[] black = _buildColor(Color.BLACK, position);
58 byte[] addition = _buildAddition(position);
61 int length = white.length + black.length + addition.length;
62 if (length % 2 == 0) {
63 bytes = _concat(white, black, addition);
65 byte[] end = {TCD.END};
66 bytes = _concat(white, black, addition, end);
69 bytes = _compress(bytes);
73 bytes, TCD.OUTPUT_CHARSET
77 private byte[] _buildColor(Color color, Position position) {
78 byte[] bytes = {Color.WHITE.equals(color) ? TCD.WHITE : TCD.BLACK};
79 for (Piece piece : Piece.values()) {
80 Map<Square, ColorPiece> squarePieces = position.getSquarePieces(color, piece);
81 if (!squarePieces.isEmpty()) {
82 byte[] pieces = new byte[2 * (squarePieces.size() + 1)];
86 pieces[i++] = TCD.PAWN;
89 pieces[i++] = TCD.KNIGHT;
92 pieces[i++] = TCD.BISHOP;
95 pieces[i++] = TCD.ROOK;
98 pieces[i++] = TCD.QUEEN;
101 pieces[i++] = TCD.KING;
104 pieces[i++] = (byte) (squarePieces.size() - 1);
105 for (Square square : squarePieces.keySet()) {
106 pieces[i++] = (byte) square.getV();
107 pieces[i++] = (byte) square.getH();
109 bytes = _concat(bytes, pieces);
115 private byte[] _buildAddition(Position position) {
116 byte[] bytes = {TCD.WHITE, TCD.BLACK};
117 if (!TCD.isDiagram() && !position.isDiagram()) {
120 _buildMove(position),
121 _buildCastle(Color.WHITE, position),
122 _buildCastle(Color.BLACK, position),
123 _buildEnPassant(position),
124 _buildHalfMove(position),
125 _buildFullMove(position)
131 private byte[] _buildMove(Position position) {
132 if (position.getMove() != null) {
135 Color.WHITE.equals(position.getMove()) ? TCD.WHITE : TCD.BLACK
141 private byte[] _buildCastle(Color color, Position position) {
142 Castle castle = position.getCastle(color);
143 if (castle != null) {
147 castleByte = TCD.CASTLE_KING;
150 castleByte = TCD.CASTLE_QUEEN;
153 castleByte = TCD.CASTLE_BOTH;
156 castleByte = TCD.CASTLE_NONE;
159 Color.WHITE.equals(color) ? TCD.CASTLE_WHITE : TCD.CASTLE_BLACK,
166 private byte[] _buildEnPassant(Position position) {
167 Square square = position.getEnPassant();
168 if (square != null) {
171 (byte) square.getV(),
178 private byte[] _buildHalfMove(Position position) {
179 int halfMove = position.getHalfMove();
182 (byte) (halfMove >> 2 * TCD.FRAME_LENGTH & TCD.FRAME_MASK),
183 (byte) (halfMove >> TCD.FRAME_LENGTH & TCD.FRAME_MASK),
184 (byte) (halfMove & TCD.FRAME_MASK)
188 private byte[] _buildFullMove(Position position) {
189 int fullMove = position.getFullMove();
192 (byte) (fullMove >> 2 * TCD.FRAME_LENGTH & TCD.FRAME_MASK),
193 (byte) (fullMove >> TCD.FRAME_LENGTH & TCD.FRAME_MASK),
194 (byte) (fullMove & TCD.FRAME_MASK),
198 private byte[] _concat(byte[]... byteArrays) {
200 for (byte[] bytes : byteArrays) {
201 length += bytes.length;
203 byte[] concatBytes = new byte[length];
205 for (byte[] bytes : byteArrays) {
206 if (bytes.length == 0)
208 System.arraycopy(bytes, 0, concatBytes, length, bytes.length);
209 length += bytes.length;
214 private byte[] _compress(byte[] bytes) {
215 byte[] cmpBytes = new byte[bytes.length / 2];
218 for (int j = 0; j < cmpBytes.length; ++j) {
219 high = (byte) ((bytes[i++] & TCD.FRAME_MASK) << TCD.FRAME_LENGTH);
220 low = (byte) (bytes[i++] & TCD.FRAME_MASK);
221 cmpBytes[j] = (byte) (TCD.BYTE_MASK | high | low);
226 public static Builder getInstance() {
231 public static void main(String[] args) throws ParseException {
232 Position position = Positions.EMPTY.getPosition();
235 position.setKing(Color.WHITE, Square.C1);
236 position.setQueen(Color.WHITE, Square.B3);
237 position.setRook(Color.WHITE, Square.D1);
238 position.setBishop(Color.WHITE, Square.G5);
239 position.setPawn(Color.WHITE, Square.A2);
240 position.setPawn(Color.WHITE, Square.B2);
241 position.setPawn(Color.WHITE, Square.C2);
242 position.setPawn(Color.WHITE, Square.E4);
243 position.setPawn(Color.WHITE, Square.F2);
244 position.setPawn(Color.WHITE, Square.G2);
245 position.setPawn(Color.WHITE, Square.H2);
247 position.setKing(Color.BLACK, Square.E8);
248 position.setQueen(Color.BLACK, Square.E6);
249 position.setRook(Color.BLACK, Square.H8);
250 position.setBishop(Color.BLACK, Square.F8);
251 position.setKnight(Color.BLACK, Square.D7);
252 position.setPawn(Color.BLACK, Square.A7);
253 position.setPawn(Color.BLACK, Square.E5);
254 position.setPawn(Color.BLACK, Square.F7);
255 position.setPawn(Color.BLACK, Square.G7);
256 position.setPawn(Color.BLACK, Square.H7);
260 position.setKing(Color.WHITE, Square.G1);
261 position.setQueen(Color.WHITE, Square.A4);
262 position.setRook(Color.WHITE, Square.D1);
263 position.setBishop(Color.WHITE, Square.A3);
264 position.setBishop(Color.WHITE, Square.D3);
265 position.setPawn(Color.WHITE, Square.A2);
266 position.setPawn(Color.WHITE, Square.C3);
267 position.setPawn(Color.WHITE, Square.F6);
268 position.setPawn(Color.WHITE, Square.F2);
269 position.setPawn(Color.WHITE, Square.G2);
270 position.setPawn(Color.WHITE, Square.H2);
272 position.setKing(Color.BLACK, Square.E8);
273 position.setQueen(Color.BLACK, Square.F3);
274 position.setRook(Color.BLACK, Square.B8);
275 position.setRook(Color.BLACK, Square.G8);
276 position.setBishop(Color.BLACK, Square.B7);
277 position.setBishop(Color.BLACK, Square.B6);
278 position.setKnight(Color.BLACK, Square.E7);
279 position.setPawn(Color.BLACK, Square.A7);
280 position.setPawn(Color.BLACK, Square.C7);
281 position.setPawn(Color.BLACK, Square.D7);
282 position.setPawn(Color.BLACK, Square.F7);
283 position.setPawn(Color.BLACK, Square.H7);
286 position.setKing(Color.WHITE, Square.H1);
287 position.setQueen(Color.WHITE, Square.E3);
288 position.setRook(Color.WHITE, Square.E1);
289 position.setRook(Color.WHITE, Square.G1);
290 position.setBishop(Color.WHITE, Square.D2);
291 position.setBishop(Color.WHITE, Square.G2);
292 position.setKnight(Color.WHITE, Square.B1);
293 position.setPawn(Color.WHITE, Square.A2);
294 position.setPawn(Color.WHITE, Square.B2);
295 position.setPawn(Color.WHITE, Square.D4);
296 position.setPawn(Color.WHITE, Square.G3);
297 position.setPawn(Color.WHITE, Square.H3);
299 position.setKing(Color.BLACK, Square.G8);
300 position.setQueen(Color.BLACK, Square.D7);
301 position.setRook(Color.BLACK, Square.F5);
302 position.setRook(Color.BLACK, Square.F2);
303 position.setBishop(Color.BLACK, Square.D6);
304 position.setBishop(Color.BLACK, Square.D3);
305 position.setPawn(Color.BLACK, Square.A6);
306 position.setPawn(Color.BLACK, Square.B4);
307 position.setPawn(Color.BLACK, Square.D5);
308 position.setPawn(Color.BLACK, Square.E6);
309 position.setPawn(Color.BLACK, Square.E4);
310 position.setPawn(Color.BLACK, Square.G7);
311 position.setPawn(Color.BLACK, Square.H6);
314 position.setKing(Color.WHITE, Square.H5);
315 position.setPawn(Color.WHITE, Square.C6);
316 position.setKing(Color.BLACK, Square.A6);
317 position.setPawn(Color.BLACK, Square.F6);
318 position.setPawn(Color.BLACK, Square.G7);
319 position.setPawn(Color.BLACK, Square.H6);
323 position.setMove(Color.WHITE);
325 position.setCastle(Color.WHITE, Castle.NONE);
326 position.setCastle(Color.BLACK, Castle.NONE);
328 //position.setEnPassant(Square.A3);
330 position.setHalfMove(0);
331 position.setFullMove(26);
333 TCD.setDiagram(false);
335 String tcd = getInstance().build(position);
341 Position tcdPosition = Parsers.TCD.parser().parse(tcd);
344 Builders.ASCII.builder().build(tcdPosition)
348 getInstance().build(tcdPosition)
352 Builders.FEN.builder().build(tcdPosition)
357 getInstance().build(Positions.INITIAL.getPosition())