Giter Site home page Giter Site logo

emychess's Introduction

EmyChess

Preview picture

A chess prefab for VRChat SDK3 worlds, powered by Udon, written in C# using UdonSharp

Can also be found on Booth

Featuring:

  • Fully synced board
  • Standard mode with legal move checking and game over states
  • Support for castling, pawn promotion and en passant
  • Synced timer with an automatic side switching option
  • Anarchy mode to remove move checking, and allow piece spawning/deleting

Setup

Requirements

The latest release of EmyChess is made to work with a project created with the VRChat Creator Companion, with the UdonSharp package installed. Make sure to migrate your project before installing.

Installation

  1. Download the latest release of EmyChess from here or from Booth
  2. Import the Unity package inside the project
  3. Drag the EmyChess prefab from Packages/EmyChess/Runtime into the scene
  4. Position and scale as desired

Contributing

This prefab is currently in beta, pull requests are appreciated! Refer to the task list for planned features, as well as known issues

License

All code in this repository is licensed under the GNU Public License v3.0, as stated in the license file

All other assets are licensed under Creative Commons Attribution-ShareAlike 4.0 as stated in the other license file, with the exception of:

emychess's People

Contributors

blackstartx avatar bluwizard10 avatar emymin avatar zenithval avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

emychess's Issues

Broken with the new VCC

As soon as I try to import emychess into a VCC (vrchat creator companion) project, Unity immediately pops up its crash window and proceeds to crash the project. If I then open the project back up, A prefab message saying something about unpacking will persist and not go away unless I remove emychess from the files and then re-launch the project. I know this hasnt been updated since back in 2021 but it's one of the higher quality free chess boards that I love using. If you could fix it/update it that would be amazing~

Issue with castling

Hello, I enjoy the chessboard very much but small issue with the board logic. When castling would be illegal because a bishop line of sight would prevent castling, the board still let you castle.

If you plan future updates, here is a few suggestions:
1.Have a replay mode to rewatch the last played game.
2.An export feature where you can copy(clipboard) the notation of the game at the end of a match would be awesome.

Keep up the good work!

Nuka

ui proposal

hey there i changed a little bit the UI on my project, what do you think of it?

image

image

A Tiny Issue

Hello again. I noticed a little issue with your Chess Clock... everything works great! but.... you have the Chess clock set wrong. I looked up the official time rules to be sure of this. When a Chess match starts Black side starts the clock for White... your board is set to where White starts the clock for black, that's not the correct way to start a match.

Is there a way I can correct the clock in the scene? I tried on my own but couldn't seem to tweak the clock setup.

Not Work?

I'm new to Udon side of things when it comes to VRChat so I could just be doing something wrong. I followed your directions for adding the prefab to my world, but when I go to test build none of the buttons seem to work and I can't start Chess match. I'm using the the VRChat Creator Companion; with everything up to date

EmyChess breaks when the users that are playing it leave the world

The chess board will be stuck in a "playing" state even though no one can move any pieces any no one is able to reset the game. Whoever is the master of the instance is shown as both of the current players that are playing, but they also cannot reset the board and don't see themselves as a player on the game.

pawn queen swap broken.

when the queen is of the table and a pawn to the end of the board at opponent side, the pawn to queen swap broke. the opponent gets his color queen instead of mine. but the whole game also broke and no turns can be made any more.

This is how I fixed the castle bug, hope this helps! -Phrozen

Hello, I've been working on my own version of EmmyChess and I managed to fix the castle bug. My current version is very different from the asset so I will post some of the code to fix castle for the asset. If you want to see the changes I've made to emmy chess you can check out the Vrchat Map "Cozy Space". I had to basicly not call functions directly in order to avoid the crashing issue that came up a lot, so it caused me to update bools and call the bools instead of the direct function. I hope this helps, I am very new to coding, fixing this took probably a straight month of work.

//(added to defaultrules)
//Top part -

   [HideInInspector] 
   public bool BlackLeftCastle = true;
    [HideInInspector]
    public bool BlackRightCastle = true;
    [HideInInspector]
    public bool WhiteLeftCastle = true;
    [HideInInspector]
    public bool WhiteRightCastle = true; 
    [HideInInspector]
    public bool BlackMoveLeftCastle = true;
    [HideInInspector]
    public bool BlackMoveRightCastle = true;
    [HideInInspector]
    public bool WhiteMoveLeftCastle = true;
    [HideInInspector]
    public bool WhiteMoveRightCastle = true;
    [HideInInspector]
    public bool WhitePiecesRightCastle = false;
    [HideInInspector]
    public bool WhitePiecesLeftCastle = false;
    [HideInInspector]
    public bool BlackPiecesRightCastle = false;
    [HideInInspector]
    public bool BlackPiecesLeftCastle = false;      //I also added all these exactly the same to start() might not be important.
    [HideInInspector]
    [UdonSynced]
    public bool CastleInCheck = false;

//Added functions -

// (pseudolegalmoves)

else if (type == "king")
{
for (int i = -1; i < 2; i++)
{
for (int j = -1; j < 2; j++)
{
Piece squarepiece = board.GetGridPiece(x + i, y + j, grid);
if (squarepiece == null || (squarepiece != null && squarepiece.white != white))
{
index = AppendMove(index, x + i, y + j, legalMoves);
}
}
}
if (white)
{
if (WhiteRightCastle && WhiteMoveRightCastle && WhitePiecesRightCastle && !CastleInCheck)
{
index = AppendMove(index, x + 2, y, legalMoves);
}
if (WhiteLeftCastle && WhiteMoveLeftCastle && WhitePiecesLeftCastle && !CastleInCheck)
{
index = AppendMove(index, x - 2, y, legalMoves);
}
}
else
{
if (BlackRightCastle && BlackMoveRightCastle && BlackPiecesRightCastle && !CastleInCheck)
{
index = AppendMove(index, x + 2, y, legalMoves);
}
if (BlackLeftCastle && BlackMoveLeftCastle && BlackPiecesLeftCastle && !CastleInCheck)
{
index = AppendMove(index, x - 2, y, legalMoves);
}
}
}

//(iskingincheck)
if (opponentPseudoLegalMove == legalMovesEndMarker) { break; }
else
{
if (opponentPseudoLegalMove == threatenedPos)
{
isKingChecked = true;
CastleInCheck = true; //this is all thats added in order to not directly call iskingincheck
break;
}
}

//(new)

    public void CastleMoveCheck()
    {
        WhiteMoveRightCastle = true;
        BlackMoveRightCastle = true;
        WhiteMoveLeftCastle = true;
        BlackMoveLeftCastle = true;
        RequestSerialization();
    }
    public void CastleNotMoved(Piece movedPiece)
    {
        if (movedPiece.type == "king")
        {
            if (movedPiece.white)
            {
                WhiteMoveRightCastle = false;
                WhiteMoveLeftCastle = false;
            }
            else
            {
                BlackMoveRightCastle = false;
                BlackMoveLeftCastle = false;
            }
        }
        else if (movedPiece.type == "rook")
        {
            if (movedPiece.white)
            {
                if (movedPiece.x == 0 && movedPiece.y == 0) // Left rook initial position for white
                {
                    WhiteMoveLeftCastle = false;
                }
                else if (movedPiece.x == 7 && movedPiece.y == 0) // Right rook initial position for white
                {
                    WhiteMoveRightCastle = false;
                }
            }
            else
            {
                if (movedPiece.x == 0 && movedPiece.y == 7) // Left rook initial position for black
                {
                    BlackMoveLeftCastle = false;
                }
                else if (movedPiece.x == 7 && movedPiece.y == 7) // Right rook initial position for black
                {
                    BlackMoveRightCastle = false;
                }
            }
        }
        RequestSerialization();
    }

    public void CheckCastlePaths(Piece[] grid, Board board)
    {
         if (grid == null) { Debug.LogWarning("Empty grid, might be first turn"); return; }

        // Check White Right Castle
        WhitePiecesRightCastle = true;
        for (int i = 5; i < 7; i++) // Check squares between king and right rook for white
        {
            if (board.GetGridPiece(i, 0, grid) != null) // Assuming white's back rank is y = 0
            {
                WhitePiecesRightCastle = false;
                break;
            }
        }

        // Check White Left Castle
        WhitePiecesLeftCastle = true;
        for (int i = 1; i < 4; i++) // Check squares between king and left rook for white
        {
            if (board.GetGridPiece(i, 0, grid) != null) // Assuming white's back rank is y = 0
            {
                WhitePiecesLeftCastle = false;
                break;
            }
        }

        // Check Black Right Castle
        BlackPiecesRightCastle = true;
        for (int i = 5; i < 7; i++) // Check squares between king and right rook for black
        {
            if (board.GetGridPiece(i, 7, grid) != null) // Assuming black's back rank is y = 7
            {
                BlackPiecesRightCastle = false;
                break;
            }
        }

        // Check Black Left Castle
        BlackPiecesLeftCastle = true;
        for (int i = 1; i < 4; i++) // Check squares between king and left rook for black
        {
            if (board.GetGridPiece(i, 7, grid) != null) // Assuming black's back rank is y = 7
            {
                BlackPiecesLeftCastle = false;
                break;
            }
        }
        RequestSerialization();
    }
    public void CheckCastleSafety(Piece[] grid, Board board)
    {
        // Check squares next to the White King
        Vector2 whiteKingPos = board.whiteKing.GetVec();
        WhiteLeftCastle = !(IsSquareUnderAttack((int)whiteKingPos.x - 1, (int)whiteKingPos.y, false, grid, board) ||
                            IsSquareUnderAttack((int)whiteKingPos.x - 2, (int)whiteKingPos.y, false, grid, board));

        WhiteRightCastle = !(IsSquareUnderAttack((int)whiteKingPos.x + 1, (int)whiteKingPos.y, false, grid, board) ||
                             IsSquareUnderAttack((int)whiteKingPos.x + 2, (int)whiteKingPos.y, false, grid, board));

        // Check squares next to the Black King
        Vector2 blackKingPos = board.blackKing.GetVec();
        BlackLeftCastle = !(IsSquareUnderAttack((int)blackKingPos.x - 1, (int)blackKingPos.y, true, grid, board) ||
                            IsSquareUnderAttack((int)blackKingPos.x - 2, (int)blackKingPos.y, true, grid, board));

        BlackRightCastle = !(IsSquareUnderAttack((int)blackKingPos.x + 1, (int)blackKingPos.y, true, grid, board) ||
                             IsSquareUnderAttack((int)blackKingPos.x + 2, (int)blackKingPos.y, true, grid, board));
        RequestSerialization();
    }
    private bool IsSquareUnderAttack(int x, int y, bool byWhite, Piece[] grid, Board board)
    {
        foreach (Piece piece in board.GetAllPieces())
        {
            if (piece.white == byWhite)
            {
                Vector2[] pseudoLegalMoves = GetAllPseudoLegalMovesGrid(piece, grid, board.PawnThatDidADoublePushLastRound, 
              board);
                foreach (Vector2 move in pseudoLegalMoves)
                {
                    if (move == legalMovesEndMarker) break;
                    if (move.x == x && move.y == y)
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }

//(modified GetAlllegalMoves)

    public Vector2[] GetAllLegalMoves(Piece movedPiece, Board board)
    {
        Vector2[] pseudoLegalMoves = GetAllPseudoLegalMovesGrid(movedPiece, board.grid, board.PawnThatDidADoublePushLastRound, board);
        Vector2 piecePos = movedPiece.GetVec();
        Piece king = movedPiece.white ? board.whiteKing : board.blackKing;
        if (king != null)
        {
            Vector2 kingPos = king.GetVec();
            Piece[] currentGrid = board.grid;
            Piece[] testGrid = new Piece[currentGrid.Length];
            CastleInCheck = false;    // Reset CastleInCheck to false initially   <-----only line added.
            for (int i = 0; i < pseudoLegalMoves.Length; i++)
            {
                Vector2 pseudoLegalMove = pseudoLegalMoves[i];

                if (pseudoLegalMove == legalMovesEndMarker) { break; }
                else
                {
                    Array.Copy(currentGrid, testGrid, currentGrid.Length);

                    board.MoveGridPieceVec(piecePos, pseudoLegalMove, testGrid);
                    Piece PawnThatDidADoublePush = null;
                    if (movedPiece.type == "pawn" && (Mathf.Abs(movedPiece.x - (int)pseudoLegalMove.x) > 1))
                    {
                        PawnThatDidADoublePush = movedPiece;
                    }
                    Vector2 threatenedPos = movedPiece.type != "king" ? kingPos : pseudoLegalMove;
                    if (isKingInCheck(threatenedPos, testGrid, board, PawnThatDidADoublePush, movedPiece.white)) { pseudoLegalMoves[i] = legalMovesIgnoreMarker; }
                }
            }
        }
        return pseudoLegalMoves;
    }

//(modified Move)

    public int Move(Piece movedPiece, int x, int y, Board board)
    {
        int result = 0;
        if (anarchy)
        {
            Piece targetPiece = board.GetPiece(x, y);
            result = 1;
            if (targetPiece != null && targetPiece != movedPiece) { targetPiece._Capture(); result = 2; }
            movedPiece._SetPosition(x, y);
            return result;
        }
        else
        {
            Vector2[] legalMoves = GetAllLegalMoves(movedPiece, board);
            result = MoveLegalCheck(movedPiece, x, y, board, legalMoves);

            // Call CastleNotMoved whenever a piece is moved <---------
            if (result > 0)
            {
                CastleNotMoved(movedPiece);
            }

            return result;
        }
    }

//(modified MoveLegalCheck)

    public int MoveLegalCheck(Piece movedPiece, int x, int y, Board board, Vector2[] legalMoves)
    {
        int result = 0;
        Piece targetPiece = board.GetPiece(x, y);
        Vector2 move = new Vector2(x, y);
        bool legal = false;
        foreach (Vector2 legalMove in legalMoves)
        {
            if (legalMove != legalMovesIgnoreMarker)
            {
                if (legalMove == legalMovesEndMarker) break;
                if (move == legalMove) { legal = true; break; }
            }
        }
        if (legal)
        {
            if (targetPiece != null) { targetPiece._Capture(); result = 2; } else { result = 1; }

            if (movedPiece.type == "pawn" && movedPiece.x != x && board.GetPiece(x, y) == null) //EN PASSANT
            {
                board.PawnThatDidADoublePushLastRound._Capture();
                result = 2;
            }

            if (movedPiece.type == "king")
            {
                if (movedPiece.white)
                {
                    if (x - movedPiece.x == 2 && WhiteRightCastle && WhiteMoveRightCastle && WhitePiecesRightCastle && !CastleInCheck) // White right castle
                    {
                        Piece rookCastle = board.GetPiece(7, y);
                        rookCastle._SetPosition(x - 1, y);
                    }
                    else if (x - movedPiece.x == -2 && WhiteLeftCastle && WhiteMoveLeftCastle && WhitePiecesLeftCastle && !CastleInCheck) // White left castle
                    {
                        Piece rookCastle = board.GetPiece(0, y);
                        rookCastle._SetPosition(x + 1, y);
                    }
                }
                else
                {
                    if (x - movedPiece.x == 2 && BlackRightCastle && BlackMoveRightCastle && BlackPiecesRightCastle && !CastleInCheck) // Black right castle 
                    {
                        Piece rookCastle = board.GetPiece(7, y);
                        rookCastle._SetPosition(x - 1, y);
                    }
                    else if (x - movedPiece.x == -2 && BlackLeftCastle && BlackMoveLeftCastle && BlackPiecesLeftCastle && !CastleInCheck) // Black left castle
                    {
                        Piece rookCastle = board.GetPiece(0, y);
                        rookCastle._SetPosition(x + 1, y);
                    }
                }
            }

            if (movedPiece.type == "pawn" && Mathf.Abs(y - movedPiece.y) == 2)
            {
                board.PawnThatDidADoublePushLastRound = movedPiece;
            }
            else
            {
                board.PawnThatDidADoublePushLastRound = null;
            }
            CastleNotMoved(movedPiece);
            movedPiece.hasMoved = true;
            movedPiece._SetPosition(x, y);

            return result;
        }
        else
        {
            movedPiece._SetPosition(movedPiece.x, movedPiece.y);
            return 0;
        }
    }

//(Board.cs Changes - Removed the castle move from board.cs)

    public void MoveGridPiece(int ox, int oy, int tx, int ty, Piece[] grid)
    {
        Piece piece = GetGridPiece(ox, oy, grid);
        // No en passant or castling logic
        SetGridPiece(tx, ty, piece, grid);
        SetGridPiece(ox, oy, null, grid);
    }


    /// <summary>
    /// Simulate a piece's move on a grid, including capture, en passant and castling
    /// </summary>
    /// <param name="original">Starting position</param>
    /// <param name="target">Target position</param>
    /// <param name="grid"></param>
    public void MoveGridPieceVec(Vector2 original, Vector2 target, Piece[] grid)
    {
        MoveGridPiece((int)original.x, (int)original.y, (int)target.x, (int)target.y, grid);
    }

//(Chessmanger Changes)

//(Endturn)
board.currentRules.CheckCastlePaths(board.grid, board); // Check castle paths at end turn <-added
board.currentRules.CheckCastleSafety(board.grid, board); // Check castle safety at end turn<-added
_RefreshUI();
RequestSerialization();

//(startgame)
board.currentRules.CheckCastlePaths(board.grid, board); // Check castle paths at game start
board.currentRules.CheckCastleSafety(board.grid, board); // Check castle safety at game start

//(endgame)
board.currentRules.CastleMoveCheck();

How do i make it work

I have downloaded the UdonSharp and Vrchat . but its not functional, should I reconfigure all of these?
image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.