/* * 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.fen; import java.util.regex.Pattern; import org.hedgecode.chess.position.Color; import org.hedgecode.chess.position.ParseException; import org.hedgecode.chess.position.Parser; import org.hedgecode.chess.position.Position; import org.hedgecode.chess.position.Positions; import org.hedgecode.chess.position.Square; /** * Forsyth–Edwards Notation (FEN) parser. * * @author Dmitry Samoshin aka gotty */ public final class FENParser implements Parser { private static final String SPLIT_REGEX = "\\s+"; private static final String LINE_REGEX = FEN.LINE_SEP; private static final Pattern PATTERN = Pattern.compile( String.format("^(%s){%d} (%s) (%s) (%s) (%s) (%s)$", FEN.Fields.PIECES.regex(), Square.getSize(), FEN.Fields.MOVE.regex(), FEN.Fields.CASTLE.regex(), FEN.Fields.EN_PASSANT.regex(), FEN.Fields.HALFMOVE.regex(), FEN.Fields.FULLMOVE.regex() ) ); /* private static final Pattern PATTERN = Pattern.compile( "^([pPnNbBrRqQkK1-8]+/?)* [wb] [qQkK]+|- ([a-h][36])|- [0-9]+ [1-9][0-9]*$" ); */ private static Parser _instance = new FENParser(); private FENParser() { } public boolean isValidFen(String fen) { return PATTERN.matcher(fen).matches(); } @Override public Position parse(String string) throws ParseException { if (string == null) throw new ParseException("parse.null.input.string"); if (!isValidFen(string)) throw new ParseException("parse.fen.invalid.string"); Position position = Positions.EMPTY.getPosition(); String[] fields = string.split(SPLIT_REGEX); _parsePieces( fields[FEN.Fields.PIECES.index()], position ); _parseMove( fields[FEN.Fields.MOVE.index()], position ); _parseCastle( fields[FEN.Fields.CASTLE.index()], position ); _parseEnPassant( fields[FEN.Fields.EN_PASSANT.index()], position ); _parseHalfMove( fields[FEN.Fields.HALFMOVE.index()], position ); _parseFullMove( fields[FEN.Fields.FULLMOVE.index()], position ); return position; } private void _parsePieces(String fen, Position position) throws ParseException { String[] lines = fen.split(LINE_REGEX); if (lines.length != Square.getSize()) throw new ParseException("parse.fen.incorrect.board"); for (int i = 0; i < lines.length; ++i) { int hLine = lines.length - (i + 1); int vLine = 0; char[] pieces = lines[i].toCharArray(); for (char piece : pieces) { if (vLine >= Square.getSize()) throw new ParseException("parse.fen.incorrect.board"); if (Character.isDigit(piece)) { int num = Character.getNumericValue(piece); if (vLine + num > Square.getSize()) throw new ParseException("parse.fen.incorrect.board"); for (int j = 0; j < num; ++j) { position.setPiece( null, Square.getSquare(vLine, hLine) ); vLine++; } } else { position.setPiece( FEN.getColorPiece(piece), Square.getSquare(vLine, hLine) ); vLine++; } } } } private void _parseMove(String move, Position position) { position.setMove( FEN.getColor(move.charAt(0)) ); } private void _parseCastle(String castle, Position position) { position.setCastle( Color.WHITE, FEN.getCastle(Color.WHITE, castle) ); position.setCastle( Color.BLACK, FEN.getCastle(Color.BLACK, castle) ); } private void _parseEnPassant(String enPassant, Position position) { position.setEnPassant( FEN.getEnPassant(enPassant) ); } private void _parseHalfMove(String halfMove, Position position) { position.setHalfMove( Integer.parseInt(halfMove) ); } private void _parseFullMove(String fullMove, Position position) { position.setFullMove( Integer.parseInt(fullMove) ); } public static Parser getInstance() { return _instance; } public static void main(String[] args) throws ParseException { /* Pattern pattern = Pattern.compile( "^([pPnNbBrRqQkK1-8]+/?){8} [wb] ([qQkK]+|-) ([a-h][36]|-) [0-9]+ [1-9][0-9]*$" ); System.out.println( pattern.matcher("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - a6 0 1").matches() ); */ Position position = getInstance().parse( //"rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1" "r7/7p/8/8/8/8/PPPPPP2/1N1Q2NR w KQkq a3 20 20" ); System.out.println(position); } }