Ultimate Chess

Ultimate Chess is an new take on chess. Featuring new pieces, a larger board, and the ability to place your own pieces before the match starts. This was my first group SE project. Given my game development experience I acted as team lead on this project. I created the grid, board manager, and the parent piece object.

Downloads

Technical Information

Project Details

IDE: Unity/Visual Studio
Languages: C#
Stage: Final

List of Features

  • Before the match starts players place their pieces until they reach a maximum value of total pieces
  • When selecting a piece the game shows you what spaces it can move to as well as any pieces it can take
  • Check detection
  • The game manages turn order
  • Save game/Load game system
  • OO principles are used to allow quick addition/modification of piece behavior

  • The bulk of the game exists in the board manager class. It is responsible for tracking who's turn it is, location of the pieces, and if the king is in check. The latter data is stored as part of a 3D array. The first two dimensions are x and y positions of the board. The 3rd dimension has 2 layers. Piece type and piece color. The bottom left of the grid rests at (0,0,0). When the player clicks on the screen it sends a raycast towards the grid and returns the cooridnates of the collision. These values are divided by the size of each grid space then rounded down. The board manager then checks to see what piece is in that position and proceeds accordingly.


    To define movement behaviour the CreateMarker method is called for each space that piece can move to. The method has 3 arguments. Relative X position, Relative Y position, and Type. The type has 3 states. 2 is the most common. This is used for any space a piece can move to, and take at. The others are primarly used for pawns. 0 is used for any space a piece can move to, but cannot take at. 1 is used for a space a piece can ONLY take at, but cannot normally move to.

    Example Piece Definitions

    public class King : Piece  {
    	public override void Movement() {
    		base.CreateMarker(0, 1, 2);
    		base.CreateMarker(0, -1, 2);
    		base.CreateMarker(1, 0, 2);
    		base.CreateMarker(-1, 0, 2);
    		base.CreateMarker(1, 1, 2);
    		base.CreateMarker(1, -1, 2);
    		base.CreateMarker(-1, 1, 2);
    		base.CreateMarker(-1, -1, 2);
    	}
    }
    public class Pawn : Piece {
    	public override void Movement() {
    		if(color == 0) {
    			base.CreateMarker(0, 1, 0);
    			base.CreateMarker(-1, 1, 1);
    			base.CreateMarker(1, 1, 1);
    		}
    		//Snip//
    	}
    }
    
    public class Rook : Piece {
    	public override void Movement() {
    		int i = 1;
    		int stopped = 0;
    		while (stopped==0) { //up
    			base.CreateMarker(0, i, 2);
    			//If next is out of bounds, or colliding with another piece
    			if (y + i >= 9) or (GameObject.FindWithTag("Grid").GetComponent().boardState[x, y + i, 0] != 0)
    				stopped = 1;
    			i++;     
    		}
    		//Snip//
    	}
    }

    What I learned

    This project offered a few new experiences. Ultimate Chess was the first time I used unity or C# beyond following a simple youtube tutorial. Ultimate Chess was also the first time I worked with others on a project's code base. The most important lesson I learned with this project were coding paradigms. The CS class I had taken this semester taught us C++ and functional design. I groundwork of this project was laid using functional design, as I had learned. When a more experianced student had asked why we weren't taking better advantage of the object-oriented nature of Unity I learned about design paradigms. The pieces themselves were refactored but the board manager is still almost entirely functional

    This project is also a good example of how my code has evolved over the years. The following are examples of code used to display where a piece can move after being clicked on


    public class Piece : MonoBehaviour
    {
    	//Snip//
    	public void OnMouseDown()
    	{
    		//Snip//
    	}
    
    	//Snip//
    
    	public void CreateMarker (int rx, int ry, int type)
    	{
    		if ((x + rx >= 0) && (x + rx <= 9) && (y + ry >= 0) && (y + ry <= 9)) //If not out of bounds
    		{
    			if (GameObject.FindWithTag("Grid").GetComponent().gameState - 2 == color)
    			{  // Same color
    				bool empty = false;
    				if (GameObject.FindWithTag("Grid").GetComponent().boardState[x + rx, y + ry, 0] == 0)
    					empty = true;
    				bool opponent = false;
    				if (GameObject.FindWithTag("Grid").GetComponent().boardState[x + rx, y + ry, 1] != color)
    					opponent = true;
    
    				//Move Only
    				if ((type == 0) && (empty == true))
    					InstantiateMarker(rx, ry, type);
    				//Take Only
    				if ((type == 1) && (empty == false) && (opponent == true))
    					InstantiateMarker(rx, ry, type);
    				//Move/Take
    				if ((type == 2) && ((empty == true) || (opponent == true)))
    					InstantiateMarker(rx, ry, type);
    			}
    			else // Different color
    			{
    				if ((GameObject.FindWithTag("Grid").GetComponent().boardState[x + rx, y + ry, 1] != color) && (GameObject.FindWithTag("Grid").GetComponent().boardState[x + rx, y + ry, 0] == 1) && (type > 0))
    				{
    					GameObject.FindWithTag("Grid").GetComponent().check = true;
    				}
    			}
    		}
    	}
    
    	public void InstantiateMarker(int rx, int ry, int type)
    	{
    		//Snip//
    	}
    		
    	public virtual void Movement ()
    	{
    		//Snip//
    	}
    }

    public class Piece : MonoBehaviour {
    	//Snip//
    	const int MOVE = 0;
    	const int TAKE = 1;
    	const int MOVETAKE = 2;
    	const int KING = 1; { get; private set; }
    
    	void OnMouseDown() {
    		//Snip//
    	}
    	//Snip//
    	void CreateMarker (int relativeX, int relativeY, int type) {
    		BoardManager boardManager = GameObject.FindWithTag("Grid").GetComponent();
    		Vector2Int position = new Vector2Int(x + relativeX, y + relativeY);
    		if (isInBounds(position)) {      
    			if (boardManager.getActivePlayer() == color) {                
    				if ((type == MOVE)     && (IsEmpty(position)))
    					InstantiateMarkerMove(position);
    				if ((type == TAKE)     && (!IsEmpty(position)) && (IsOpponent(position)))
    					InstantiateMarkerTake(position);
    				if ((type == MOVETAKE) && ((IsEmpty(position)) || (IsOpponent(position))))
    					InstantiateMarkerTake(position);
    			}
    			else if ((type > MOVE) && (IsOpponent(position)) && (boardManager.GetPieceAt(position) == KING))
    				boardManager.check = true;
    		}
    	}
    
    	virtual void Movement () {
    	}
    
    	void InstantiateMarkerMove(Vector2Int position) {
    		//Snip//
    	}
    
    	void InstantiateMarkerTake(Vector2Int position) {
    		//Snip//
    	}
    
    	bool IsInBounds(Vector2Int position) {
    		if ((position.x >= 0) && (position.x <= 9) && (position.y >= 0) && (position.y <= 9)); return true; else return false;
    	}
    
    	bool IsEmpty(Vector2Int position) {
    		if (boardManager.GetPieceAt(position) == 0); return true; else return false;
    	}
    
    	bool IsOpponent(Vector2Int position) {
    		if (boardManager.GetColorAt(position) != color); return true; else return false;
    	}
    }

    Image Gallery

    Image 1

    Image 2

    Image 3

    Image 4

    Back to Top