Search code examples
c#unity-game-enginechessfen

Create FEN string in Unity after reading Chess Board


I made a fully functional chess game in Unity using C#. Now i want to add AI, for the chess engine i went with Stockfish. I got the engine inside the game but it does nothing because it cant communicate with the board.

To communicate i need to make a FEN string per row, starting on the top left, the FEN string looks like this:

rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1

lower case are black pieces, upper case white pieces, the numbers are black spaces, w means white turn next, KQkq means that castling in available, - means en passant is available and 0 1 number of moves.

Does anyone know of a tutorial, or tips to create and manipulate strings to make the FEN string?

I will paste the code i have done so far towards the Stockfish Process, i haven't done anything related to the FEN string because i don't really know how to start it.

Any links or tips are welcome

void RunProcess()
{
    ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.UseShellExecute = false;
    startInfo.RedirectStandardInput = true;
    startInfo.RedirectStandardOutput = true;
    startInfo.RedirectStandardError = false;
    startInfo.CreateNoWindow = true;
    startInfo.FileName = Application.streamingAssetsPath + "/stockfish_9_x64.exe";

    Process process = new Process();
    process.StartInfo = startInfo;
    process.Start();

    string output;

    process.StandardInput.WriteLine("uci");
    process.StandardInput.WriteLine("isready");
    process.StandardInput.WriteLine("position fen rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1");
    process.StandardInput.WriteLine("go");
    process.StandardInput.WriteLine("stop");
    process.StandardInput.WriteLine("quit");

    do
    {
        output = process.StandardOutput.ReadLine();
    } while (!output.Contains("move"));

    UnityEngine.Debug.Log(output);
}

void OnMouseDown()
{
    RunProcess();
}

Solution

  • Just to get the basic piece, you could do something like (note: not tested):

    public enum ChessPieces
    {
        King, Queen, Rook, // ... etc. 
    }
    
    public class ChessPiece : MonoBehavior
    {
        public string FenId { get; }
    
        private readonly Dictionary<ChessPiece, string> FenIds = {
            { ChessPieces.King, "K" },
            { ChessPieces.Queen, "Q" },
            // ... etc.
        };
    
        // assuming you create the set of pieces programatically, use this constructor
        public ChessPiece(ChessPiece piece, ChessColor color)
        {
            FenId = color == ChessColor.Black 
                ? FenIds[piece].ToLower() 
                : FenIds[piece].ToUpper();
        }
    }
    

    Then, assuming you are storing your board in an array of rows, to dump the layout into a string I'd probably override ToString on my ChessBoard class (also not tested):

    // somewhere in your code set the board up
    _chessBoard.Rows.Add(new [] {
        new ChessPiece(ChessPieces.Rook, ChessColor.Black),
        new ChessPiece(ChessPieces.Knight, ChessColor.Black),
        // ... etc.
        })
    _chessBoard.Rows.Add(new [] { /* next row ... */ });
    // ... etc.
    
    // to create your output, put this into the override of ToString:
    var output = ""; // should be StringBuilder, but for clarity and since this isn't likely performance limiting...
    var rowIndex = 0;
    foreach (var row in _chessBoard.Rows)
    {
        rowIndex++;
        var blankSpaces = 0;
    
        foreach(var piece in row)
        {
            if (piece == null) 
            {
                blankSpaces++;
            }
            else
            {
                output += blankSpaces == 0 
                    ? piece.FenId
                    : string.Format("{0}{1}", blankspaces, piece.FenId);
                blankSpaces = 0;
            }
    
            if (blankSpaces > 0)
            {
                output += blankSpaces;
            }
        }
    
        if (rowIndex != 8)
        {
            output += "/";
        }
    }
    

    At this point you've got your basic layout in a string and you should have the basic idea for adding the other FEN fields.

    I should note that I've selected a collection of arrays for storing your board. That probably isn't the most efficient storage mechanism (i.e. in the best case you're storing 50% empty values, which will only increase as the game progresses), but since we're only talking about 64 items total we're probably okay on memory.