250211

lililllilillll·2025년 2월 11일

개발 일지

목록 보기
79/350

✅ 오늘 한 일


  • Project BCA


🎮 Project BCA


Delete mode

Stockfish에 FEN을 계속 넘겨줄 때 성능 저하가 심각한가?

✅ FEN 방식이 moves 방식보다 약간 성능 저하가 있지만, 실전에서는 차이가 거의 없음.
✅ Stockfish는 스마트폰에서도 초당 수백만 개의 포지션을 계산할 수 있어서 여전히 인간을 압도함.
✅ 엔진 대 엔진 매치처럼 깊은 탐색(30수 이상)이 필요할 때는 moves 방식이 더 빠름.

기본 구현

    /// <summary>
    /// 플레이어가 플레이어 턴에 마우스 좌클하면 호출되어 기물 선택, 이동, 삭제를 처리하는 함수
    /// </summary>
    public void HandleClick(bool whiteTurn)
    {
        GameObject clickedObject = ClickObject();

        if (deleteMode)
        {
            HandleEnemyPieces(whiteTurn, clickedObject);
            return;
        }

        HandleMyPieces(whiteTurn, clickedObject);
    }

    private void HandleEnemyPieces(bool whiteTurn, GameObject clickedObject)
    {
        // 선택한 오브젝트가 없고, 클릭한 오브젝트가 적 기물이라면 삭제
        if (clickedObject != null && clickedObject.GetComponent<Piece>().isWhite != whiteTurn)
        {
            (int, int) clickedGridIdx = board.BoardPosToGridIdx(clickedObject.transform.position);
            board.DestroyPieceAt(clickedGridIdx.Item1, clickedGridIdx.Item2);
        }
        DisableDeleteMode();
    }

    public void EnableDeleteMode()
    {
        deleteMode = true;
    }

    public void DisableDeleteMode()
    {
        deleteMode = false;
    }

Generating FEN string

FEN의 마지막 두 필드

  1. 50수 규칙 카운트 (5번째 필드):

    • 마지막 폰 이동 또는 기물 잡기 이후 경과한 반수(half-move) 횟수
    • 50수 규칙(50턴 동안 폰 이동이나 기물 잡기가 없으면 무승부) 적용에 사용됨
    • 반 수 : 백 또는 흑이 움직일 때마다 1씩 오른다.
    • 0으로 초기화한 직후에는 증가시키면 안 되고, 평소에는 흑이 둔 후마다 증가
  2. 턴 카운트 (6번째 필드):

    • 흑의 수까지 포함한 전체 턴 수 (1부터 시작)
    • 흑의 차례가 끝날 때마다 증가
    • 예를 들어, 1.e4를 둔 후 1이 아닌 2가 됨 (백이 둔 후 증가 X, 흑이 둔 후 증가 O)
    • 한 수 : 흑이 움직였을 때 1씩 오른다.
 /// ------------------------------------------------------------------------------------------------------------------------------
    /// FEN 관련 함수들
    /// ------------------------------------------------------------------------------------------------------------------------------

    public string getFENstring()
    {
        string fen = "";
        fen += FEN_Pieces() + " ";
        fen += "b "; // FEN string은 AI만 사용하므로, 무조건 b로 기록
        fen += FEN_Castling() + " ";
        fen += FEN_EnPassant() + " ";
        fen += FEN_HalfMoveClock() + " ";
        fen += FEN_FullMoveNumber();
        return fen;
    }

    private string FEN_Pieces()
    {
        string fen_pieces = "";

        for (int y = 8; y >= 1; y--)
        {
            int empty = 0;
            for (int x = 1; x <= 8; x++)
            {
                if (GetPieceAt(x, y) == null)
                {
                    empty++;
                }
                else
                {
                    if (empty != 0)
                    {
                        fen_pieces += empty.ToString();
                        empty = 0;
                    }
                    fen_pieces += GetPieceAt(x, y).GetComponent<Piece>().GetFENchar();
                }
            }
            if (empty != 0)
            {
                fen_pieces += empty.ToString();
            }
            if (y != 1)
            {
                fen_pieces += "/";
            }
        }

        return fen_pieces;
    }

    private string FEN_Castling()
    {
        string fen_castling = "";
        if (BothFirstMove((1, 1), (5, 1))) fen_castling += "K";
        if (BothFirstMove((8, 1), (5, 1))) fen_castling += "Q";
        if (BothFirstMove((1, 8), (5, 8))) fen_castling += "k";
        if (BothFirstMove((8, 8), (5, 8))) fen_castling += "q";
        if (fen_castling == "") fen_castling = "-";
        return fen_castling;
    }

    private bool BothFirstMove((int, int) p1, (int, int) p2)
    {
        Piece p1_script = GetPieceScriptAt(p1.Item1, p1.Item2);
        Piece p2_script = GetPieceScriptAt(p2.Item1, p2.Item2);
        if (p1_script == null || p2_script == null) return false;
        return p1_script.FirstMove && p2_script.FirstMove;
    }

    private string FEN_EnPassant()
    {
        string fen_enpassant = "";
        (int ep_x, int ep_y) = moveValidator.blackEnPassantCandidate;
        if ((ep_x, ep_y) != (-1, -1)) fen_enpassant = aiManager.GridToUCI(ep_x, ep_y);
        else fen_enpassant = "-";
        return fen_enpassant;
    }

    private string FEN_HalfMoveClock()
    {
        return halfMoveCount.ToString();
    }

    public void ResetHalfMoveCount()
    {
        halfMoveCount = 0;
    }

    public void IncreaseHalfMoveCount()
    {
        halfMoveCount++;
    }

    private string FEN_FullMoveNumber()
    {
        return fullMoveCount.ToString();
    }

    public void ResetFullMoveCount()
    {
        fullMoveCount = 1;
    }

    public void IncreaseFullMoveCount()
    {
        fullMoveCount++;
    }

Board.cs

        // 50수 규칙을 위한 카운트
        if (destroyed || pieceScript is Pawn) board.ResetHalfMoveCount();
        else board.IncreaseHalfMoveCount();

        if (!gameManager.whiteTurn) board.IncreaseFullMoveCount(); // 흑 끝나면 전체 턴 수 증가

InputHandler.cs :: MoveTo()

profile
너 정말 **핵심**을 찔렀어

0개의 댓글