为了账号安全,请及时绑定邮箱和手机立即绑定

阅读棋盘后在Unity中创建FEN字符串

阅读棋盘后在Unity中创建FEN字符串

C#
www说 2022-08-20 16:08:41
我使用C#在Unity中制作了一个功能齐全的国际象棋游戏。现在我想添加AI,对于国际象棋引擎,我选择了Stockfish。我在游戏中安装了引擎,但它什么也没做,因为它无法与棋盘通信。要进行通信,我需要每行创建一个FEN字符串,从左上角开始,FEN字符串如下所示:rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1小写是黑色的棋子,大写的白色棋子,数字是黑色的空格,w表示白色的下一个转弯,KQkq表示可用的施法,-表示通过是可用的,0 1个移动次数。有没有人知道创建和操作字符串以制作FEN字符串的教程或提示?我将把我到目前为止所做的代码粘贴到Stockfish进程中,我没有做任何与FEN字符串相关的事情,因为我真的不知道如何启动它。欢迎任何链接或提示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();}
查看完整描述

2 回答

?
侃侃尔雅

TA贡献1801条经验 获得超16个赞

只是为了获得基本部分,你可以做这样的事情(注意:未测试):


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();

    }

}

然后,假设您将电路板存储在行数组中,将布局转储到一个字符串中,我可能会在我的类上覆盖(也未经过测试):ToStringChessBoard


// 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 += "/";

    }

}

此时,您已经在字符串中获得了基本布局,并且应该具有添加其他FEN字段的基本想法。


我应该注意,我已经选择了一组数组来存储您的电路板。这可能不是最有效的存储机制(即在最好的情况下,你存储了50%的空值,这些值只会随着游戏的进行而增加),但是由于我们只谈论总共64个项目,因此我们可能在内存上没问题。


查看完整回答
反对 回复 2022-08-20
?
交互式爱情

TA贡献1712条经验 获得超3个赞

public void LoadFEN(string fen)

{

    //Removes all pieces

    foreach (Piece piece in pieces)

    {

        Destroy(piece.gameObject);

    }


    pieces = new List<Piece>();

    AddSquareCoordinates(); // Add "local" coordinates to all squares


    #region FENStuff

    int xPos = 0;

    int yPos = 7;

    string[] fenChunks = fen.Split(' '); //Fen parts separated

    for (int x = 0; x < fenChunks[0].Length; x++)

    {

        switch (fenChunks[0][x])

        {

            case 'K':

                PlacePiece(PieceType.King, xPos, yPos, -1);

                break;

            case 'k':

                PlacePiece(PieceType.King, xPos, yPos, 1);

                break;

            case 'Q':

                PlacePiece(PieceType.Queen, xPos, yPos, -1);

                break;

            case 'q':

                PlacePiece(PieceType.Queen, xPos, yPos, 1);

                break;

            case 'R':

                PlacePiece(PieceType.Rook, xPos, yPos, -1);

                break;

            case 'r':

                PlacePiece(PieceType.Rook, xPos, yPos, 1);

                break;

            case 'N':

                PlacePiece(PieceType.Knight, xPos, yPos, -1);

                break;

            case 'n':

                PlacePiece(PieceType.Knight, xPos, yPos, 1);

                break;

            case 'B':

                PlacePiece(PieceType.Bishop, xPos, yPos, -1);

                break;

            case 'b':

                PlacePiece(PieceType.Bishop, xPos, yPos, 1);

                break;

            case 'P':

                PlacePiece(PieceType.Pawn, xPos, yPos, -1);

                break;

            case 'p':

                PlacePiece(PieceType.Pawn, xPos, yPos, 1);

                break;

        }


        if (char.IsDigit(fenChunks[0][x]))

        {

            xPos += (int)char.GetNumericValue(fen[x]);

        }

        else

            xPos += 1;


        if (fenChunks[0][x] == '/')

        {

            yPos -= 1;

            xPos = 0;

        }

    }


    SetStartPiecesCoor(); // Update all piece's coordinate

    AddCastleRooks(); // Add rooks to the king piece

    PawnFirstSquareAdjust(); //Checks if the pawns have already moved


    curTurn = fenChunks[1] == "w" ? -1 : 1;


    //fen cadtling priviledges code

    Piece kingWhite = GetKingPiece(-1);

    Piece kingBlack = GetKingPiece(1);

    bool castleWhiteKing = true, castleWhiteQueen = true, castleBlackKing = true, castleBlackQueen = true;

    for(int i = 0; i < fenChunks[2].Length; i++)

    {

        switch(fenChunks[2][i])

        {

            case 'K':

                castleWhiteKing = false;

                break;

            case 'Q':

                castleWhiteQueen = false;

                break;

            case 'k':

                castleBlackKing = false;

                break;

            case 'q':

                castleBlackQueen = false;

                break;

        }

    }


    kingWhite.started = castleWhiteKing && castleWhiteQueen;

    if(kingWhite.castlingRooks[0] != null)

        kingWhite.castlingRooks[0].started = castleWhiteKing;

    if(kingWhite.castlingRooks[1] != null)

        kingWhite.castlingRooks[1].started = castleWhiteQueen;


    kingBlack.started = castleBlackKing && castleBlackQueen;

    if (kingBlack.castlingRooks[1] != null)

        kingBlack.castlingRooks[0].started = castleBlackKing;

    if (kingBlack.castlingRooks[1] != null)

        kingBlack.castlingRooks[1].started = castleBlackQueen;


    if (fenChunks[3] != "-")

    {

        string coordinate = fenChunks[3];

        string row = coordinate[1] == '3' ? "4" : "5";

        coordinate = coordinate[0] + row;

        GetSquareFromLetterCoordinate(coordinate).holdingPiece.enPassantAvailable = true;            

    }


    halfMoveClock = Convert.ToInt32(fenChunks[4]);

    fullMoveClock = Convert.ToInt32(fenChunks[5]);


    #endregion

    UpdateGameTheme(curTheme);

}


public void ExportFEN()

{

    int freeCellCount = 0;

    fen = "";

    for (int y = 7; y > -1; y--)

    {

        for (int x = 0; x < 8; x++)

        {

            Piece piece = GetSquareFromCoordinate(new Vector2Int(x, y)).holdingPiece;

            if (piece == null)

            {

                freeCellCount += 1;

            }

            else

            {

                if (freeCellCount != 0)

                {

                    fen += freeCellCount.ToString();

                    freeCellCount = 0;

                }

                if (piece.pieceType == PieceType.King)

                {

                    if (piece.team == -1)

                        fen += "K";

                    else

                        fen += "k";

                }

                else if (piece.pieceType == PieceType.Queen)

                {

                    if (piece.team == -1)

                        fen += "Q";

                    else

                        fen += "q";

                }

                else if (piece.pieceType == PieceType.Rook)

                {

                    if (piece.team == -1)

                        fen += "R";

                    else

                        fen += "r";

                }

                else if (piece.pieceType == PieceType.Bishop)

                {

                    if (piece.team == -1)

                        fen += "B";

                    else

                        fen += "b";

                }

                else if (piece.pieceType == PieceType.Knight)

                {

                    if (piece.team == -1)

                        fen += "N";

                    else

                        fen += "n";

                }

                else if (piece.pieceType == PieceType.Pawn)

                {

                    if (piece.team == -1)

                        fen += "P";

                    else

                        fen += "p";

                }


            }

        }

        if (freeCellCount != 0)

        {

            fen += freeCellCount.ToString();

        }

        freeCellCount = 0;

        if (y != 0)

            fen += '/';

    }


    fen += " ";

    string turnChar = curTurn == -1 ? "w" : "b";

    fen += turnChar + " ";


    Piece kingWhite = GetKingPiece(-1);

    Piece kingBlack = GetKingPiece(1);


    if (!kingWhite.started)

    {

        if (kingWhite.castlingRooks[0] != null && !kingWhite.castlingRooks[0].started)

            fen += "K";

        if (kingWhite.castlingRooks[1] != null && !kingWhite.castlingRooks[1].started)

            fen += "Q";

    }

    if (!kingBlack.started)

    {

        if (kingBlack.castlingRooks[0] != null && !kingBlack.castlingRooks[0].started)

            fen += "k";

        if (kingBlack.castlingRooks[1] != null && !kingBlack.castlingRooks[1].started)

            fen += "q";

    }

    fen += " ";


    fen += enPassantSquare + " ";


    fen += halfMoveClock.ToString() + " " + fullMoveClock.ToString();

}


private void PlacePiece(PieceType type, int xCoord, int yCoord, int team)

{

    Square square = GetSquareFromCoordinate(new Vector2Int(xCoord, yCoord));

    GameObject pieceObj;

    Piece piece;

    int prefabIndex = -1;

    switch (type)

    {

        case PieceType.King:

            prefabIndex = 0;

            break;

        case PieceType.Queen:

            prefabIndex = 1;

            break;

        case PieceType.Rook:

            prefabIndex = 2;

            break;

        case PieceType.Knight:

            prefabIndex = 3;

            break;

        case PieceType.Bishop:

            prefabIndex = 4;

            break;

        case PieceType.Pawn:

            prefabIndex = 5;

            break;

    }


    pieceObj = Instantiate(piecePrefabs[prefabIndex], pieceParent.transform);

    pieceObj.transform.position = square.transform.position;


    piece = pieceObj.GetComponent<Piece>();


    piece.team = team;

    piece.curSquare = square;

    piece.board = this;

    pieces.Add(piece);

}


private void AddCastleRooks()

{

    foreach (Piece piece in pieces)

    {


        if (piece.pieceType == PieceType.King)

        {

            if (piece.team == -1)

            {

                Piece rook1 = GetSquareFromCoordinate(new Vector2Int(7, 0)).holdingPiece;

                if (rook1 != null && rook1.pieceType == PieceType.Rook)

                    piece.castlingRooks.Add(rook1);

                else piece.castlingRooks.Add(null);


                Piece rook2 = GetSquareFromCoordinate(new Vector2Int(0, 0)).holdingPiece;

                if (rook2 != null && rook1.pieceType == PieceType.Rook)

                    piece.castlingRooks.Add(rook2);

                else piece.castlingRooks.Add(null);


            }

            else

            {

                Piece rook1 = GetSquareFromCoordinate(new Vector2Int(7, 7)).holdingPiece;

                if (rook1 != null && rook1.pieceType == PieceType.Rook)

                    piece.castlingRooks.Add(rook1);

                else piece.castlingRooks.Add(null);



                Piece rook2 = GetSquareFromCoordinate(new Vector2Int(0, 7)).holdingPiece;

                if (rook2 != null && rook1.pieceType == PieceType.Rook)

                    piece.castlingRooks.Add(rook2);

                else piece.castlingRooks.Add(null);


            }

        }

    }

}


private void PawnFirstSquareAdjust()

{

    int startRank;


    foreach (Piece piece in pieces)

    {

        startRank = piece.team == -1 ? 1 : 6;


        if (piece.pieceType == PieceType.Pawn)

        {

            if (piece.curSquare.coor.y != startRank)

            {

                piece.started = true;

            }

        }

    }

}

我还在开发我的国际象棋应用程序,我知道可能为时已晚。但希望这有帮助。


我有 PieceType 作为枚举。我想你可以找出变量。


另外,我在部分Move()函数中重置了moveClocks。


查看完整回答
反对 回复 2022-08-20
  • 2 回答
  • 0 关注
  • 209 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号