Skip to content
Permalink
4b17a24d59
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
836 lines (731 sloc) 26.8 KB
using System;
using System.Collections.Generic;
using System.Linq;
namespace ChessTest3
{
//My previous attempt did not allow for the actual printing of the game, and ended up being
//more of a guideline on how to do so.
//Also i had accidently used terms that would work in Javascript rather than C#,
//so the method in which get and set, as well as the throw keyword, were incorrect.
public class Cell
{
private int x, y;
//Establishing the individual squares that will make up our Board
public Cell(int x, int y)
{
this.x = x;
this.y = y;
}
public int X
{
get
{
return x;
}
set
{
if ((value >= 0) && (value < 8)) //The limit will be 0-8, the size of a chess board
x = value;
}
}
public int Y
{
get
{
return y;
}
set
{
if ((value >= 0) && (value < 8))
y = value;
}
}
}
//Creating the piece class; this will be very useful to refer to with the board.
abstract public class Piece
{
//Here, I use the protected keyword so the presented members of this piece class are
////accessible through the instances that it may be used outside the class
//This will identify the piece, and see what piece it is
protected char whatPiece;
//This simplifies the process, so White pieces are classified under a 1, Black pieces under a 0
protected bool isWhite;
protected Cell start;
//This indicates the starting square of a specific piece
protected Piece[,] Square;
//The actual matrix that will create the board itself
public Piece(bool isWhite, int x, int y, Piece[,] Square)
{
this.Square = Square;
this.start = new Cell(x, y);
this.isWhite = isWhite;
}
public abstract bool MoveChecker(Cell end);
public int MoveValue(Cell end, char coordinates)
{
//Math abs is essentially a method to return the absolute value of the number presented
return coordinates == 'X' ? Math.Abs(start.X - end.X) : Math.Abs(start.Y - end.Y);
}
public bool FreeSpace(Cell pos)
{
return Square[pos.X, pos.Y] != null ? (Square[pos.X, pos.Y].IsWhite != isWhite) : true;
}
public char WhatPiece
{
get
{
return whatPiece;
}
set
{
whatPiece = value;
}
}
public bool IsWhite
{
get
{
return isWhite;
}
set
{
isWhite = value;
}
}
public Cell Start
{
get
{
return start;
}
set
{
start = value;
}
}
}
//Creating the Piece classes, I will start with the Knight as that's the most complex
public class Knight : Piece
//This extends the Knight class and connects it to the Piece class so
//the program knows that they're connected
{
public Knight(bool isWhite, int x, int y, Piece[,] Square) : base(isWhite, x, y, Square)
{
whatPiece = 'H';
//H for Horse as King will be K
}
public override bool MoveChecker(Cell end)
{
//This checks that the moves are valid
int absX = MoveValue(end, 'X');
int absY = MoveValue(end, 'Y');
//This dictates the X and Y moves of the Knight.
//This method is how I'll dictate the piece movements for the knight
return ((absX == 2) && (absY == 1) || (absX == 1) && (absY == 2)) ? FreeSpace(end) : false;
}
}
//King
public class King : Piece
{
public King(bool isWhite, int x, int y, Piece[,] Square) : base(isWhite, x, y, Square)
{
whatPiece = 'K';
}
public override bool MoveChecker(Cell end)
{
return ((MoveValue(end, 'X') <= 1) && (MoveValue(end, 'Y') <= 1)) ? FreeSpace(end) : false;
}
}
//Pawn
public class Pawn : Piece
{
bool moved;
public Pawn(bool isWhite, int x, int y, Piece[,] Square) : base(isWhite, x, y, Square)
{
whatPiece = 'P';
moved = false;
}
public override bool MoveChecker(Cell end)
{
bool result = false;
int absX = MoveValue(end, 'X');
int absY = MoveValue(end, 'Y');
if (start.X == end.X)
{
if (absY == 2 && !moved)
{
if (isWhite)
{
result = !((Square[end.X, end.Y] != null) || (Square[end.X, end.Y - 1] != null));
}
else
{
result = !((Square[end.X, end.Y] != null) || (Square[end.X, end.Y + 1] != null));
}
}
else if (absY == 1)
{
result = isWhite ? (start.Y < end.Y) : (start.Y > end.Y);
if (result)
{
if (Square[end.X, end.Y] == null)
{
result = FreeSpace(end);
}
else
{
result = false;
}
}
}
}
else if (absX == 1 && absY == 1)
{
//result = Square[end.X, end.Y] != null && Square[end.X, end.Y]IsWhite != isWhite;
}
if (result)
{
moved = true;
}
return result;
}
// {
// return (MoveValue(end, 'Y') <= 1) ? FreeSpace(end) : false;
// }
//I assumed Pawns were very simple, but there are many more factors that play into a pawn
}
//Rook
public class Rook : Piece
{
public Rook(bool isWhite, int x, int y, Piece[,] Square) : base(isWhite, x, y, Square)
{
whatPiece = 'R';
}
public override bool MoveChecker(Cell end)
{
//This essentially says that if the following moves aren't attempted
//The result will be returned false and will not execute
bool result = false;
if (start.X == end.X)
//This will dictate the vertical movement
{
result = true;
for (int i = 1; ((i < MoveValue(end, 'Y')) && (result)); i++)
//this for loop is essentially saying,
//For when i = 1, up to when i = the max value it can move up the board, return the result,
//it increases i by increments of 1 to go through all the options it can take
//before reaching max value (7).
{
if (start.Y < end.Y)
//If the starting horizontal position is larger than the destination position
{
result = Square[start.X, start.Y + i] == null;
//i increases through the loop, so it will be start.Y + 1, 2, 3, etc...
}
else if (start.Y > end.Y)
{
//This does the same as the previous but in the opposite horizontal direction
result = Square[start.X, start.Y - i] == null;
}
}
}
else if (start.Y == end.Y)
//This is how the Horizontal Movement is done
{
result = true;
for (int i = 1; ((i < MoveValue(end, 'X')) && (result)); i++)
{
if (start.X < end.X)
{
result = Square[start.X + i, start.Y] == null;
}
else if (start.X < end.X)
{
result = Square[start.X - i, start.Y] == null;
}
}
}
return result ? FreeSpace(end) : result;
}
}
//Bishop
public class Bishop : Piece
{
public Bishop(bool isWhite, int x, int y, Piece[,] Square) : base(isWhite, x, y, Square)
{
whatPiece = 'B';
}
public override bool MoveChecker(Cell end)
{
bool result = false;
int absX = MoveValue(end, 'X');
int absY = MoveValue(end, 'Y');
//Diagonal Movement. The X movement and the Y movement for the bishop will always be the same for Bishop
if (absX == absY)
{
result = true;
//We have to check for any occupied squares in front of the Bishop
for (int i = 1; ((i < absX) && (result)); i++)
{
if (start.X < end.X)
{
result = start.Y < end.Y ?
!(Square[start.X + i, start.Y + i] != null) : !(Square[start.X + i, start.Y - 1] != null);
}
else
{
result = start.Y < end.Y ?
!(Square[start.X - i, start.Y + i] != null) : !(Square[start.X - i, start.Y - i] != null);
}
}
}
return result ? FreeSpace(end) : result;
}
}
//Queen, which is essentially just combining Bishop and Queen's moves
public class Queen : Piece
{
public Queen(bool isWhite, int x, int y, Piece[,] Square) : base(isWhite, x, y, Square)
{
whatPiece = 'Q';
}
public override bool MoveChecker(Cell end)
{
bool result = false;
int absX = MoveValue(end, 'X');
int absY = MoveValue(end, 'Y');
if (start.X == end.X)
{
result = true;
for (int i = 1; ((i < MoveValue(end, 'Y')) && (result)); i++)
{
if (start.Y < end.Y)
{
result = Square[start.X, start.Y + i] == null;
}
else if (start.Y > end.Y)
{
result = Square[start.X, start.Y - i] == null;
}
}
}
else if (start.Y == end.Y)
{
result = true;
for (int i = 1; ((i < MoveValue(end, 'X')) && (result)); i++)
{
if (start.X < end.X)
{
result = Square[start.X + i, start.Y] == null;
}
else if (start.X < end.X)
{
result = Square[start.X - i, start.Y] == null;
}
}
}
else if (absX == absY)
{
result = true;
for (int i = 1; ((i < absX) && (result)); i++)
{
if (start.X < end.X)
{
result = start.Y < end.Y ?
!(Square[start.X + i, start.Y + i] != null) : !(Square[start.X + i, start.Y - 1] != null);
}
else
{
result = start.Y < end.Y ?
!(Square[start.X - i, start.Y + i] != null) : !(Square[start.X - i, start.Y - i] != null);
}
}
}
return result ? FreeSpace(end) : result;
}
}
public static class ErrorChecking
{
public static void PieceCheck(bool isWhite)
{
Console.ForegroundColor = isWhite ? ConsoleColor.Yellow : ConsoleColor.Blue;
string player = isWhite ? "White" : "Black";
Console.Write("It is " + player + "'s turn! Please choose which piece to move using their X and Y coordinates, like so: (X, Y): ");
Console.ResetColor();
}
public static void Moving(bool isWhite)
{
Console.ForegroundColor = isWhite ? ConsoleColor.Yellow : ConsoleColor.Blue;
string player = isWhite ? "White" : "Black";
Console.Write("Great! Now select where you wanna move the piece, also using X and Y, like so: (X, Y)");
Console.ResetColor();
}
public static void Info(string text, ConsoleColor color = ConsoleColor.White)
{
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("[Info] " + text);
Console.ResetColor();
}
public static void GameEnd(bool isWhite)
{
Console.ForegroundColor = ConsoleColor.Green;
string player = isWhite ? "WHITE" : "BLACK";
Console.WriteLine("CHECKMATE! " + player + " has won the game!");
Console.ResetColor();
}
public static void Error(string text)
{
Console.WriteLine("[Error] " + text);
Console.Clear();
}
}
//Creating the board
public class Board
{
private Piece[,] Square;
private Cell whiteKing, blackKing;
private List<Piece> whitePieces, blackPieces;
//The king pieces are in separate classes to the other pieces as they hold different properties to other pieces
// For example, taking a King will result in a Win,
private bool checkWhite = false, checkBlack = false;
private bool checkMateWhite = false, checkMateBlack = false;
public Board()
{
Square = new Piece[8, 8]; //Size of the board is 8x8
}
//This will initialize the board and also add all the pieces onto the board.
public void Initialize()
{
whitePieces = AddPieces(true);
blackPieces = AddPieces(false);
}
private List<Piece> AddPieces(bool isWhite)
{
//List work similarly to Enums and can be accessed later
List<Piece> pieces = new List<Piece>();
int columnStart = isWhite ? 0 : 6;
int columnEnd = isWhite ? 2 : 8;
for (int i = 0; i < 8; i++)
{
for (int j = columnStart; j < columnEnd; j++)
{
if ((isWhite && j == columnStart) || (!isWhite && j != columnStart))
{
switch (i)
{
case 0:
case 7:
{
Square[i, j] = new Rook(isWhite, i, j, Square);
}
break;
case 1:
case 6:
{
Square[i, j] = new Knight(isWhite, i, j, Square);
}
break;
case 2:
case 5:
{
Square[i, j] = new Bishop(isWhite, i, j, Square);
}
break;
case 3:
{
Square[i, j] = new Queen(isWhite, i, j, Square);
}
break;
case 4:
{
Square[i, j] = new King(isWhite, i, j, Square);
if (isWhite)
{
whiteKing = Square[i, j].Start;
}
else
{
blackKing = Square[i, j].Start;
}
}
break;
}
pieces.Add(Square[i, j]);
}
else
{
Square[i, j] = new Pawn(isWhite, i, j, Square);
pieces.Add(Square[i, j]);
}
}
}
return pieces;
}
//Placing the piece Symbols and also the general shape of the board
public void TheGrid()
{
for (int j = 7; j >= 0; j--)
{
Console.Write(" ");
for (int k = 0; k < 8; k++)
{
Console.Write("---");
}
Console.WriteLine();
Console.Write((j + 1) + " | ");
for (int i = 0; i < 8; i++)
{//This gives distinct colours to both White and Black to clearly tell who is up next.
Console.ForegroundColor = IsWhiteColor(i, j) ? ConsoleColor.Yellow : ConsoleColor.Blue;
ShowPiece(i, j);
Console.ResetColor();
Console.Write(" |");
}
Console.WriteLine();
}
Console.Write(" . ");
for (int k = 0; k < 8; k++)
{
Console.Write("--- ");
}
Console.WriteLine();
Console.Write(" ");
for (int k = 0; k < 8; k++)
{
Console.Write(" " + (k + 1) + " ");
}
Console.WriteLine("\n");
}
//This should show the piece's identifiers It goes through each empty cell in the board
////that I put a piece into through the switch case earlier and fills them with their symbols
public void ShowPiece(int i, int j)
{
char piece = Square[i, j] != null ? Square[i, j].WhatPiece : ' ';
Console.Write(" " + piece);
}
public bool IsWhiteColor(int i, int j)
{
return Square[i, j] != null ? Square[i, j].IsWhite : false;
}
public bool ProcessMove(bool isWhite)
{
bool result = false;
try
{
string[] Points;
Points = Console.ReadLine().Split(',');
//Spit is used to separate the string arrays into multiple substrings.
//So in this case, These substrings will separate to communicate to the player
int startX = int.Parse(Points[0]) - 1;
int startY = int.Parse(Points[1]) - 1;
ErrorChecking.Moving(isWhite);
Points = Console.ReadLine().Split(',');
int endX = int.Parse(Points[0]) - 1;
int endY = int.Parse(Points[1]) - 1;
if (Move(startX, startY, endX, endY, isWhite))
{
result = true;
TheGrid();
if (checkWhite)
{ //If either opponent is in check, the Info string will let the opposing player know
ErrorChecking.Info("Check on the white King", ConsoleColor.Green);
}
if (checkBlack)
{
ErrorChecking.Info("Check on the black King", ConsoleColor.Green);
}
}
}
catch (SystemException)
{ //This should prevent crashes when user inputs incorrectly when typing coordinates
//This is an exception ot the other error checks as it's concerning
//What the user has actually inputted into the program
ErrorChecking.Error("Wrong Input format, should be: X, Y, try again");
}
return result;
}
private bool InBoard(int startX, int startY, int endX, int endY)
{
return (startX >= 0 && startX < 8) && (startY >= 0 && startY < 8) && (endX >= 0 && endX < 8) && (endY >= 0 && endY < 8);
}
public bool Move(int startX, int startY, int endX, int endY, bool isWhite)
{
bool result = false;
if (InBoard(startX, startY, endX, endY))
{
Piece piece = Square[startX, startY];
Cell end = new Cell(endX, endY);
if (piece != null)
{
if (piece.IsWhite == isWhite)
{
if ((startX != endX) || (startY != endY))
{
if (piece.MoveChecker(end))
{
result = true;
if (piece.Start == whiteKing)
{
whiteKing = end;
}
if (piece.Start == blackKing)
{
blackKing = end;
}
if (Square[endX, endY] != null)
{
if (Square[endX, endY].IsWhite)
{
whitePieces.Remove(Square[endX, endY]);
}
else
{
blackPieces.Remove(Square[endX, endY]);
}
}
piece.Start = end;
Square[endX, endY] = piece;
Square[startX, startY] = null;
piece = null;
if (Verified(Square[endX, endY].IsWhite))
{
if (Square[endX, endY].IsWhite)
{
checkMateWhite = true;
}
else
{
checkMateBlack = true;
}
}
else
{
if (Square[endX, endY].IsWhite)
{
checkBlack = Verified(!Square[endX, endY].IsWhite);
}
else
{
checkWhite = Verified(!Square[endX, endY].IsWhite);
}
}
}
else
{
ErrorChecking.Error("That move is invalid! please try again!");
}
}
else
{
ErrorChecking.Error("Start and end position can't be the same! Don't stay there");
}
}
else
{
ErrorChecking.Error("You can't move the enemy's forces! Try again");
}
}
else
{
ErrorChecking.Error("Ummm....there is no piece there, try again");
}
}
else
{
ErrorChecking.Error("Those positions aren't on this board! Try again!");
}
return result;
}
private bool Verified(bool isWhite)
{
bool result = false;
if (isWhite)
{
foreach (Piece piece in blackPieces)
{
if (piece.MoveChecker(whiteKing))
{
result = true;
}
}
}
else
{
foreach (Piece piece in whitePieces)
{
if (piece.MoveChecker(blackKing))
{
result = true;
}
}
}
return result;
}
public bool CheckWhite
{
get
{
return checkWhite;
}
}
public bool CheckBlack
{
get
{
return checkBlack;
}
}
public bool CheckMateWhite
{
get
{
return checkMateWhite;
}
}
public bool CheckMateBlack
{
get
{
return checkMateBlack;
}
}
}
class program
{
public static void Main(string[] args)
{
Console.BackgroundColor = ConsoleColor.White;
Console.WriteLine("Welcome to the chess game! Would you like a standard game or a custom game? Type S for standard, or C for custom");
string input = Console.ReadLine();
if (input == "S" || input == "s")
{
Console.WriteLine("Let the Games begin!");
Board board = new Board();
board.Initialize();
board.TheGrid();
while (!board.CheckMateWhite && !board.CheckMateBlack)
{
do
{
ErrorChecking.PieceCheck(true);
}
while (!board.ProcessMove(true));
Console.WriteLine();
do
{
ErrorChecking.PieceCheck(false);
}
while (!board.ProcessMove(false));
Console.WriteLine();
}
ErrorChecking.GameEnd(board.CheckMateBlack);
Console.ReadKey();
}
else if (input == "C" || input == "c")
{
string text = System.IO.File.ReadAllText(@"C:");
System.Console.WriteLine(text);
System.Console.ReadKey();
}
}
}
}