3
\$\begingroup\$

(Part 1 here)

I've recently created my own 2-player chess game, no AI... at least for now. I do plan to do that in the future, so one of my concerns is if the code is flexible enough to just use the same classes in all the different modes so I can avoid rewriting the same code over and over again.

Resuming with the other Figure implementations.


RookPiece Class :

public sealed class RookPiece : Figure
{
    public RookPiece(FigureDefinition definition) : base(definition)
    {
        Moves = RemoveFailedTurns(this, GetValidTurns());
        Moves = Moves.Distinct().ToList();
    }

    protected override List<Tuple<int, int>> GetValidTurns()
    {
        int n = 1;
        Tuple<int, int> rightMove = new Tuple<int, int>(CurrentPosition.Item1, CurrentPosition.Item2 + n);
        Tuple<int, int> topMove = new Tuple<int, int>(CurrentPosition.Item1 + n, CurrentPosition.Item2);
        Tuple<int, int> leftMove = new Tuple<int, int>(CurrentPosition.Item1, CurrentPosition.Item2 - n);
        Tuple<int, int> downMove = new Tuple<int, int>(CurrentPosition.Item1 - n, CurrentPosition.Item2);
        List<Tuple<int, int>> startingMoves = new List<Tuple<int, int>>
        {
            rightMove,
            topMove,
            leftMove,
            downMove
        };
        List<Tuple<int, int>> validMoves =
            startingMoves.Where(
                startingMove =>
                    !IsOutOfBounds(startingMove) && !WillCollideWithAlly(startingMove, PieceColor))
                .ToList();

        while (!IsOutOfBounds(rightMove) && !WillCollideWithAlly(rightMove, PieceColor) &&
               !WillCollideWithEnemy(rightMove, PieceColor).Item1)
        {
            validMoves.Add(rightMove);
            n++;
            rightMove = new Tuple<int, int>(CurrentPosition.Item1, CurrentPosition.Item2 + n);
            if (WillCollideWithEnemy(rightMove, PieceColor).Item1)
            {
                validMoves.Add(rightMove);
                break;
            }
        }

        n = 1;
        while (!IsOutOfBounds(topMove) && !WillCollideWithAlly(topMove, PieceColor) &&
               !WillCollideWithEnemy(topMove, PieceColor).Item1)
        {
            validMoves.Add(topMove);
            n++;
            topMove = new Tuple<int, int>(CurrentPosition.Item1 + n, CurrentPosition.Item2);
            if (WillCollideWithEnemy(topMove, PieceColor).Item1)
            {
                validMoves.Add(topMove);
                break;
            }
        }

        n = 1;
        while (!IsOutOfBounds(leftMove) && !WillCollideWithAlly(leftMove, PieceColor) &&
               !WillCollideWithEnemy(leftMove, PieceColor).Item1)
        {
            validMoves.Add(leftMove);
            n++;
            leftMove = new Tuple<int, int>(CurrentPosition.Item1, CurrentPosition.Item2 - n);
            if (WillCollideWithEnemy(leftMove, PieceColor).Item1)
            {
                validMoves.Add(leftMove);
                break;
            }
        }

        n = 1;
        while (!IsOutOfBounds(downMove) && !WillCollideWithAlly(downMove, PieceColor) &&
               !WillCollideWithEnemy(downMove, PieceColor).Item1)
        {
            validMoves.Add(downMove);
            n++;
            downMove = new Tuple<int, int>(CurrentPosition.Item1 - n, CurrentPosition.Item2);
            if (WillCollideWithEnemy(downMove, PieceColor).Item1)
            {
                validMoves.Add(downMove);
                break;
            }
        }
        return validMoves;
    }
}

RookDefinitions Class :

public class RookDefinitions
{
    private static readonly GeneratePieces generatedPieces = new GeneratePieces(Figure.FigureType.Rook, 0, 7, 7,
        ImagePaths.WhiteRookImagePath, ImagePaths.BlackRookImagePath);

    public IEnumerable<FigureDefinition> WhiteRooks = generatedPieces.GenerateWhitePieces();
    public IEnumerable<FigureDefinition> BlackRooks = generatedPieces.GenerateBlackPieces();
}

QueenPiece Class :

public sealed class QueenPiece : Figure
{
    public QueenPiece(FigureDefinition definition) : base(definition)
    {
        Moves = RemoveFailedTurns(this, GetValidTurns());
        Moves = Moves.Distinct().ToList();
    }

    protected override List<Tuple<int, int>> GetValidTurns()
    {
        List<Tuple<int, int>> rookMoves = GetRookMoves();
        List<Tuple<int, int>> bishopMoves = GetBishopMoves();
        List<Tuple<int, int>> validMoves = rookMoves.ToList();
        validMoves.AddRange(bishopMoves);
        return validMoves;
    }

    private List<Tuple<int, int>> GetRookMoves()
    {
        int n = 1;
        Tuple<int, int> rightMove = new Tuple<int, int>(CurrentPosition.Item1, CurrentPosition.Item2 + n);
        Tuple<int, int> topMove = new Tuple<int, int>(CurrentPosition.Item1 + n, CurrentPosition.Item2);
        Tuple<int, int> leftMove = new Tuple<int, int>(CurrentPosition.Item1, CurrentPosition.Item2 - n);
        Tuple<int, int> downMove = new Tuple<int, int>(CurrentPosition.Item1 - n, CurrentPosition.Item2);
        List<Tuple<int, int>> startingMoves = new List<Tuple<int, int>>
        {
            rightMove,
            topMove,
            leftMove,
            downMove
        };
        List<Tuple<int, int>> validMoves =
            startingMoves.Where(
                startingMove =>
                    !IsOutOfBounds(startingMove) && !WillCollideWithAlly(startingMove, PieceColor))
                .ToList();

        while (!IsOutOfBounds(rightMove) && !WillCollideWithAlly(rightMove, PieceColor) &&
               !WillCollideWithEnemy(rightMove, PieceColor).Item1)
        {
            validMoves.Add(rightMove);
            n++;
            rightMove = new Tuple<int, int>(CurrentPosition.Item1, CurrentPosition.Item2 + n);
            if (WillCollideWithEnemy(rightMove, PieceColor).Item1)
            {
                validMoves.Add(rightMove);
                break;
            }
        }

        n = 1;
        while (!IsOutOfBounds(topMove) && !WillCollideWithAlly(topMove, PieceColor) &&
               !WillCollideWithEnemy(topMove, PieceColor).Item1)
        {
            validMoves.Add(topMove);
            n++;
            topMove = new Tuple<int, int>(CurrentPosition.Item1 + n, CurrentPosition.Item2);
            if (WillCollideWithEnemy(topMove, PieceColor).Item1)
            {
                validMoves.Add(topMove);
                break;
            }
        }

        n = 1;
        while (!IsOutOfBounds(leftMove) && !WillCollideWithAlly(leftMove, PieceColor) &&
               !WillCollideWithEnemy(leftMove, PieceColor).Item1)
        {
            validMoves.Add(leftMove);
            n++;
            leftMove = new Tuple<int, int>(CurrentPosition.Item1, CurrentPosition.Item2 - n);
            if (WillCollideWithEnemy(leftMove, PieceColor).Item1)
            {
                validMoves.Add(leftMove);
                break;
            }
        }

        n = 1;
        while (!IsOutOfBounds(downMove) && !WillCollideWithAlly(downMove, PieceColor) &&
               !WillCollideWithEnemy(downMove, PieceColor).Item1)
        {
            validMoves.Add(downMove);
            n++;
            downMove = new Tuple<int, int>(CurrentPosition.Item1 - n, CurrentPosition.Item2);
            if (WillCollideWithEnemy(downMove, PieceColor).Item1)
            {
                validMoves.Add(downMove);
                break;
            }
        }
        return validMoves;
    }

    private List<Tuple<int, int>> GetBishopMoves()
    {
        int n = 1;
        Tuple<int, int> rightUpDiagonal = new Tuple<int, int>(CurrentPosition.Item1 + n, CurrentPosition.Item2 + n);
        Tuple<int, int> leftUpDiagonal = new Tuple<int, int>(CurrentPosition.Item1 + n, CurrentPosition.Item2 - n);
        Tuple<int, int> rightDownDiagonal = new Tuple<int, int>(CurrentPosition.Item1 - n, CurrentPosition.Item2 + n);
        Tuple<int, int> leftDownDiagonal = new Tuple<int, int>(CurrentPosition.Item1 - n, CurrentPosition.Item2 - n);
        List<Tuple<int, int>> startingMoves = new List<Tuple<int, int>>
        {
            rightUpDiagonal,
            leftUpDiagonal,
            rightDownDiagonal,
            leftDownDiagonal
        };
        List<Tuple<int, int>> validMoves =
            startingMoves.Where(
                startingMove =>
                    !IsOutOfBounds(startingMove) && !WillCollideWithAlly(startingMove, PieceColor))
                .ToList();

        while (!IsOutOfBounds(rightUpDiagonal) && !WillCollideWithAlly(rightUpDiagonal, PieceColor) &&
               !WillCollideWithEnemy(rightUpDiagonal, PieceColor).Item1)
        {
            validMoves.Add(rightUpDiagonal);
            n++;
            rightUpDiagonal = new Tuple<int, int>(CurrentPosition.Item1 + n, CurrentPosition.Item2 + n);
            if (WillCollideWithEnemy(rightUpDiagonal, PieceColor).Item1)
            {
                validMoves.Add(rightUpDiagonal);
                break;
            }
        }

        n = 1;
        while (!IsOutOfBounds(leftUpDiagonal) && !WillCollideWithAlly(leftUpDiagonal, PieceColor) &&
               !WillCollideWithEnemy(leftUpDiagonal, PieceColor).Item1)
        {
            validMoves.Add(leftUpDiagonal);
            n++;
            leftUpDiagonal = new Tuple<int, int>(CurrentPosition.Item1 + n, CurrentPosition.Item2 - n);
            if (WillCollideWithEnemy(leftUpDiagonal, PieceColor).Item1)
            {
                validMoves.Add(leftUpDiagonal);
                break;
            }
        }

        n = 1;
        while (!IsOutOfBounds(rightDownDiagonal) && !WillCollideWithAlly(rightDownDiagonal, PieceColor) &&
               !WillCollideWithEnemy(rightDownDiagonal, PieceColor).Item1)
        {
            validMoves.Add(rightDownDiagonal);
            n++;
            rightDownDiagonal = new Tuple<int, int>(CurrentPosition.Item1 - n, CurrentPosition.Item2 + n);
            if (WillCollideWithEnemy(rightDownDiagonal, PieceColor).Item1)
            {
                validMoves.Add(rightDownDiagonal);
                break;
            }
        }

        n = 1;
        while (!IsOutOfBounds(leftDownDiagonal) && !WillCollideWithAlly(leftDownDiagonal, PieceColor) &&
               !WillCollideWithEnemy(leftDownDiagonal, PieceColor).Item1)
        {
            validMoves.Add(leftDownDiagonal);
            n++;
            leftDownDiagonal = new Tuple<int, int>(CurrentPosition.Item1 - n, CurrentPosition.Item2 - n);
            if (WillCollideWithEnemy(leftDownDiagonal, PieceColor).Item1)
            {
                validMoves.Add(leftDownDiagonal);
                break;
            }
        }
        return validMoves;
    }
}

QueenDefinitions Class :

public class QueenDefinitions
{
    private static readonly GeneratePieces generatedPices = new GeneratePieces(Figure.FigureType.Queen, 3, 3, 1,
        ImagePaths.WhiteQueenImagePath, ImagePaths.BlackQueenImagePath);

    public IEnumerable<FigureDefinition> WhiteQueens = generatedPices.GenerateWhitePieces();
    public IEnumerable<FigureDefinition> BlackQueens = generatedPices.GenerateBlackPieces();
}

KingPiece Class :

public sealed class KingPiece : Figure
{
    public KingPiece(FigureDefinition definition) : base(definition)
    {
        Moves = RemoveFailedTurns(this, GetValidTurns());
        Moves = Moves.Distinct().ToList();
    }

    protected override List<Tuple<int, int>> GetValidTurns()
    {
        List<Tuple<int, int>> tempMoves = new List<Tuple<int, int>>
        {
            new Tuple<int, int>(CurrentPosition.Item1 + 1, CurrentPosition.Item2),
            new Tuple<int, int>(CurrentPosition.Item1, CurrentPosition.Item2 + 1),
            new Tuple<int, int>(CurrentPosition.Item1 - 1, CurrentPosition.Item2),
            new Tuple<int, int>(CurrentPosition.Item1, CurrentPosition.Item2 - 1),
            new Tuple<int, int>(CurrentPosition.Item1 + 1, CurrentPosition.Item2 + 1),
            new Tuple<int, int>(CurrentPosition.Item1 + 1, CurrentPosition.Item2 - 1),
            new Tuple<int, int>(CurrentPosition.Item1 - 1, CurrentPosition.Item2 + 1),
            new Tuple<int, int>(CurrentPosition.Item1 - 1, CurrentPosition.Item2 - 1)
        };
        List<Tuple<int, int>> validMoves =
            tempMoves.Where(
                tempMove =>
                    !IsOutOfBounds(tempMove) && !WillCollideWithAlly(tempMove, PieceColor))
                .ToList();
        return validMoves;
    }
}

KingDefinitions Class :

public class KingDefinitions
{
    private static readonly GeneratePieces generatedPieces = new GeneratePieces(Figure.FigureType.King, 4, 4, 1,
        ImagePaths.WhiteKingImagePath, ImagePaths.BlackKingImagePath);

    public IEnumerable<FigureDefinition> BlackKings = generatedPieces.GenerateBlackPieces();
    public IEnumerable<FigureDefinition> WhiteKings = generatedPieces.GenerateWhitePieces();
}

Every FigureDefinition class uses a class called GeneratePieces. So here it is it basically shortens more repetitive code. It uses the FigureDefinition class which you can see in part 1:

public class GeneratePieces
{
    private readonly FigureType pieceType;
    private readonly int startingRowWhite = 0;
    private readonly int startingRowBlack = 7;
    private readonly int startingColumn;
    private readonly int endingColumn;
    private readonly int increase;
    private readonly string whitePieceImagePath;
    private readonly string blackPieceImagePath;

    public GeneratePieces(FigureType pieceType,int startingColumn,int endingColumn,int increase, string whitePieceImagePath, string blackPieceImagePath)
    {
        this.pieceType = pieceType;
        this.startingColumn = startingColumn;
        this.endingColumn = endingColumn;
        this.increase = increase;
        this.whitePieceImagePath = whitePieceImagePath;
        this.blackPieceImagePath = blackPieceImagePath;
        if (pieceType == FigureType.Pawn)
        {
            startingRowWhite = 1;
            startingRowBlack = 6;
        }
    }

    public IEnumerable<FigureDefinition> GenerateBlackPieces()
    {
        List<FigureDefinition> pieces = new List<FigureDefinition>();

        for (int i = startingColumn; i <= endingColumn; i += increase)
        {
            CooperativeForm.Board[startingRowBlack][i] = true;
            FigureDefinition piece = new FigureDefinition
            {
                PieceColor = FigureColor.Black,
                PieceType = pieceType,
                PieceImage = Image.FromFile(blackPieceImagePath),
                StartingPosition = new Tuple<int, int>(startingRowBlack, i),
                CurrentPosition = new Tuple<int, int>(startingRowBlack, i),
                WasMoved = false
            };
            pieces.Add(piece);

        }
        return pieces;
    }

    public IEnumerable<FigureDefinition> GenerateWhitePieces()
    {
        List<FigureDefinition> pieces = new List<FigureDefinition>();

        for (int i = startingColumn; i <= endingColumn; i += increase)
        {
            CooperativeForm.Board[startingRowWhite][i] = true;
            FigureDefinition piece = new FigureDefinition
            {
                PieceColor = FigureColor.White,
                PieceType = pieceType,
                PieceImage = Image.FromFile(whitePieceImagePath),
                StartingPosition = new Tuple<int, int>(startingRowWhite, i),
                CurrentPosition = new Tuple<int, int>(startingRowWhite, i),
            };
            pieces.Add(piece);
        }

        return pieces;
    }
}

We also have the public static Class ImagePaths which basically holds some locations of the figure's images :

public static class ImagePaths
{
    private const string assetsPath = @"Assets\Figures\";

    public static string BlackPawnImagePath { get; } = assetsPath + @"Black\b-peshka.png";
    public static string WhitePawnImagePath { get; } = assetsPath + @"White\w-peshka.png";

    public static string BlackKnightImagePath { get; } = assetsPath + @"Black\b-kon.png";
    public static string WhiteKnightImagePath { get; } = assetsPath + @"White\w-kon.png";

    public static string BlackBishopImagePath { get; } = assetsPath + @"Black\b-oficer.png";
    public static string WhiteBishopImagePath { get; } = assetsPath + @"White\w-oficer.png";

    public static string BlackRookImagePath { get; } = assetsPath + @"Black\b-top.png";
    public static string WhiteRookImagePath { get; } = assetsPath + @"White\w-top.png";

    public static string BlackQueenImagePath { get; } = assetsPath + @"Black\b-kralica.png";
    public static string WhiteQueenImagePath { get; } = assetsPath + @"White\w-kralica.png";

    public static string BlackKingImagePath { get; } = assetsPath + @"Black\b-kral.png";
    public static string WhiteKingImagePath { get; } = assetsPath + @"White\w-kral.png";
}

The CooperativeModeForm also use's the Rochade Class which is implemented like this :

using static GLS_Chess.Figures.Figure;
public class Rochade
{
    private enum RochadesByColor
    {
        White,
        Black
    }
    public Figure RochadeRook { get; private set; } = null;
    public Figure RochadeKing { get; private set; } = null;
    private static readonly List<Tuple<int, int>[]> longRochadeMoves = new List<Tuple<int, int>[]>
    {
        new[] {new Tuple<int, int>(0, 2), new Tuple<int, int>(0, 3)},
        new[] {new Tuple<int, int>(7, 2), new Tuple<int, int>(7, 3)},
    };

    private static readonly List<Tuple<int, int>[]> shortRochadeMoves = new List<Tuple<int, int>[]>
    {
        new[] {new Tuple<int, int>(0, 6), new Tuple<int, int>(0, 5)},
        new[] {new Tuple<int, int>(7, 6), new Tuple<int, int>(7, 5)},
    };

    public static Tuple<int, int> newKingMove { get; set; }

    public void DoRochade(Figure kingToBeMoved)
    {
        if (kingToBeMoved.PieceType != FigureType.King ||
            !Equals(kingToBeMoved.CurrentPosition, kingToBeMoved.StartingPosition) || kingToBeMoved.WasMoved ||
            kingToBeMoved.WillCollideWithEnemy(newKingMove, kingToBeMoved.PieceColor).Item1 ||
            kingToBeMoved.WillCollideWithAlly(newKingMove, kingToBeMoved.PieceColor))
        {
            return;
        }
        List<Figure> currentTeamFigures = kingToBeMoved.PieceColor == FigureColor.Black
            ? CooperativeForm.BlackFigures
            : CooperativeForm.WhiteFigures;
        List<Figure> enemyTeamFigures = kingToBeMoved.PieceColor == FigureColor.Black
            ? CooperativeForm.WhiteFigures
            : CooperativeForm.BlackFigures;
        if (enemyTeamFigures.Any(enemyTeamFigure => enemyTeamFigure.Moves.Contains(kingToBeMoved.CurrentPosition)))
        {
            return;
        }
        foreach (var currentAllyFigure in currentTeamFigures.Where(figure => figure.PieceType == FigureType.Rook))
        {
            if (!IsLongRochade(kingToBeMoved, currentAllyFigure) &&
                !IsShortRochade(kingToBeMoved, currentAllyFigure))
            {
                continue;
            }
            List<Tuple<int, int>[]> rochadeMoves = IsLongRochade(kingToBeMoved, currentAllyFigure)
                ? longRochadeMoves
                : shortRochadeMoves;

            int rochadeArrayIndex = currentAllyFigure.PieceColor == FigureColor.Black
                ? (int) RochadesByColor.Black
                : (int) RochadesByColor.White;

            RochadeRook = new RookPiece(new FigureDefinition
            {
                StartingPosition = currentAllyFigure.StartingPosition,
                CurrentPosition = rochadeMoves[rochadeArrayIndex][1],
                PieceColor = currentAllyFigure.PieceColor,
                PieceType = FigureType.Rook,
                PieceImage = currentAllyFigure.PieceImage,
                WasMoved = true
            });
            RochadeKing = new KingPiece(new FigureDefinition
            {
                StartingPosition = currentAllyFigure.StartingPosition,
                CurrentPosition = rochadeMoves[rochadeArrayIndex][0],
                PieceColor = currentAllyFigure.PieceColor,
                PieceType = FigureType.King,
                PieceImage = kingToBeMoved.PieceImage,
                WasMoved = true
            });
            break;
        }
    }
    private static bool IsLongRochade(Figure king, Figure rook)
    {
        bool found = longRochadeMoves.Any(t => Equals(t[0], newKingMove));
        if (!found)
        {
            return false;
        }
        int arrayIndex = king.PieceColor == FigureColor.White ? 0 : 1;
        if (Equals(rook.CurrentPosition, rook.StartingPosition))
        {
            return longRochadeMoves.Where((t, i) => rook.Moves.Contains(longRochadeMoves[arrayIndex][i])).Any();
        }
        return false;
    }
    private static bool IsShortRochade(Figure king, Figure rook)
    {
        bool found = shortRochadeMoves.Any(t => Equals(t[0], newKingMove));
        if (!found)
        {
            return false;
        }
        int arrayIndex = king.PieceColor == FigureColor.White ? 0 : 1;
        if (Equals(rook.CurrentPosition, rook.StartingPosition))
        {
            return shortRochadeMoves.Where((t, i) => rook.Moves.Contains(shortRochadeMoves[arrayIndex][i])).Any();
        }
        return false;
    }
}

And we also have the PassedTurn Class which makes the Turn Tracking feature possible :

public class PassedTurns
{
    public enum ListsOrder
    {
        WhitePlayer,
        BlackPlayer,
        PieceType,
        Action
    }

    public enum ItemsOrder
    {
        Position,
        PieceType,
        Action
    }
    private object Actions = new object();
    private object Positions = new object();
    private object PieceTypes = new object();

    public void AddNewMove(Tuple<int, int> newTurnPosition, FigureType newTurnPieceType, string newTurnAction)
    {
        Actions = newTurnAction;
        Positions = newTurnPosition;
        PieceTypes = newTurnPieceType;
    }

    public List<object> GetPassedTurns()
    {
        return new List<object>
        {
            Positions,
            PieceTypes,
            Actions,
        };
    }
}

Reaching the end of the post board

Lastly (phew!), the ReplacePawnForm is invoked whenever a pawn reaches the end of the board and must be replaced with a figure chosen by the user:

ReplacePawn form

public partial class ReplacePawnForm : Form
{
    private enum ImageIndexes
    {
        Queen,
        Rook,
        Bishop,
        Knight
    }
    public Figure ReplacedFigure { get; private set; }

    private FigureType replacedFigureType;
    private string[] imagePaths;
    private readonly PictureBox[] piecesPictureBoxs = new PictureBox[4];
    private readonly Panel[] piecesPanels = new Panel[4];
    private bool pressedPictureBox = false;
    private readonly Tuple<int, int> pawnCurrentPosition;
    private readonly FigureColor pieceColor;

    private readonly FigureType[] pieceTypes =
    {
        FigureType.Queen, FigureType.Rook,
        FigureType.Bishop, FigureType.Knight,
    };

    public ReplacePawnForm(FigureColor pieceColor,Tuple<int,int> pawnCurrentPosition)
    {
        InitializeComponent();
        SetImagePaths(pieceColor);
        SetPanels();
        SetPictureBoxs();
        CreateLabels();
        this.pieceColor = pieceColor;
        this.pawnCurrentPosition = pawnCurrentPosition;
    }

    private void bDone_Click(object sender, EventArgs e)
    {
        if (!pressedPictureBox)
        {
            MessageBox.Show(@"You haven't picked a figure yet !");
        }
        else
        {
            SetReplacedFigure();
            Close();
        }
    }

    private void SetImagePaths(FigureColor inputPieceColor)
    {
        if (inputPieceColor == FigureColor.Black)
        {
            imagePaths = new[]
            {
                ImagePaths.BlackQueenImagePath, ImagePaths.BlackRookImagePath, ImagePaths.BlackBishopImagePath,
                ImagePaths.BlackKnightImagePath
            };
        }
        else
        {
            imagePaths = new[]
            {
                ImagePaths.WhiteQueenImagePath, ImagePaths.WhiteRookImagePath, ImagePaths.WhiteBishopImagePath,
                ImagePaths.WhiteKnightImagePath
            };
        }
    }

    private void SetPanels()
    {
        int horizontal = 20;
        const int vertical = 55;
        for (int i = 0; i < piecesPanels.Length; i++)
        {
            piecesPanels[i] = new Panel
            {
                Location = new Point(horizontal,vertical),
                Size = new Size(105,95)
            };
            Controls.Add(piecesPanels[i]);
            horizontal += 125;
        }
    }
    private void SetPictureBoxs()
    {
        for (int i = 0; i < piecesPictureBoxs.Length; i++)
        {
            piecesPictureBoxs[i] = new PictureBox
            {
                BackgroundImage = Image.FromFile(imagePaths[i]),
                BackgroundImageLayout = ImageLayout.Stretch,
                Size = new Size(100,90),
                Name = i.ToString()
            };
            piecesPictureBoxs[i].Click += PictureBox_Click;
            Controls.Add(piecesPictureBoxs[i]);
            piecesPanels[i].Controls.Add(piecesPictureBoxs[i]);
        }
    }
    private void PictureBox_Click(object sender, EventArgs e)
    {
        RemoveBackgroundColor();
        pressedPictureBox = true;
        PictureBox currentPb = (PictureBox) sender;
        GetContainerPanel(currentPb).BackColor = Color.DarkCyan;
        replacedFigureType = GetFigureType(currentPb);
    }

    private FigureType GetFigureType(Control currentPb)
    {
        for (int i = 0; i < imagePaths.Length; i++)
        {
            if (currentPb.Name == i.ToString())
            {
                return pieceTypes[i];
            }
        }
        return FigureType.Queen;
    }
    private Panel GetContainerPanel(Control currentPb)
    {
        return piecesPanels.FirstOrDefault(piecesPanel => piecesPanel.Controls.Contains(currentPb));
    }

    private void RemoveBackgroundColor()
    {
        foreach (var piecesPanel in piecesPanels)
        {
            piecesPanel.BackColor = DefaultBackColor;
        }
    }

    private void CreateLabels()
    {
        Label[] labels = new Label[piecesPictureBoxs.Length];
        for (int i = 0; i < labels.Length; i++)
        {
            labels[i] = new Label
            {
                Location =
                    new Point(piecesPanels[i].Location.X + piecesPanels[i].Width/4,
                        piecesPanels[i].Location.Y + piecesPanels[i].Height),
                Text = pieceTypes[i].ToString(),
                Font = new Font("Arial", 10, FontStyle.Bold)
            };
            Controls.Add(labels[i]);
        }
    }

    private void SetReplacedFigure()
    {
        switch (replacedFigureType)
        {
            case FigureType.Bishop:
                ReplacedFigure = new BishopPiece(new FigureDefinition
                {
                    PieceType = FigureType.Bishop,
                    PieceImage = Image.FromFile(imagePaths[(int) ImageIndexes.Bishop]),
                    CurrentPosition = pawnCurrentPosition,
                    StartingPosition = pawnCurrentPosition,
                    PieceColor = pieceColor,
                    WasMoved = true
                });
                break;
            case FigureType.Knight:
                ReplacedFigure = new KnightPiece(new FigureDefinition
                {
                    PieceType = FigureType.Knight,
                    PieceImage = Image.FromFile(imagePaths[(int) ImageIndexes.Knight]),
                    CurrentPosition = pawnCurrentPosition,
                    StartingPosition = pawnCurrentPosition,
                    PieceColor = pieceColor,
                    WasMoved = true
                });
                break;
            case FigureType.Rook:
                ReplacedFigure = new RookPiece(new FigureDefinition
                {
                    PieceType = FigureType.Rook,
                    PieceImage = Image.FromFile(imagePaths[(int) ImageIndexes.Rook]),
                    CurrentPosition = pawnCurrentPosition,
                    StartingPosition = pawnCurrentPosition,
                    PieceColor = pieceColor,
                    WasMoved = true
                });
                break;
            case FigureType.Queen:
                ReplacedFigure = new QueenPiece(new FigureDefinition
                {
                    PieceType = FigureType.Queen,
                    PieceImage = Image.FromFile(imagePaths[(int) ImageIndexes.Queen]),
                    CurrentPosition = pawnCurrentPosition,
                    StartingPosition = pawnCurrentPosition,
                    PieceColor = pieceColor,
                    WasMoved = true
                });
                break;
        }
    }
}
\$\endgroup\$
1
  • 1
    \$\begingroup\$ There are a number of different points to make in each post, but also a number of points that apply to both. I don't think you had to list all implementations of Figure; one interesting piece and then apply what you learn to the rest of 'em, and then follow-up with another post that shows improvements from the previous reviews, perhaps applied to another interesting piece. That way you post more digestible code that earns you more in-depth reviews. Please take a minute to read this meta post. \$\endgroup\$ Commented May 11, 2016 at 2:14

1 Answer 1

3
\$\begingroup\$
  • Some of the terminology you're using is unusual. I would say Piece or Man instead of Figure, and "castling" instead of "Rochade". GetValidTurns should probably be called GetValidMoves.
  • As Eric Lippert suggests on your other question, you should probably create a struct called BoardPosition which contains a row and a column as ints.
    • The code for BoardPosition should contain comments indicating how the ranks and files are numbered. Maybe the constructor should check that the given numbers are in range.
    • It would be useful for BoardPosition to have a method public BoardPosition Move(int right, int up) which returns a new BoardPosition with the coordinates altered appropriately.
  • If you wanted, you could make GetValidTurns on QueenPiece just a single line: return GetRookMoves().Concat(GetBishopMoves()).ToList();
  • The methods GetValidTurns on RookPiece and GetRookMoves on QueenPiece are very similar. Consider replacing these two methods with a single GetRookMoves method. You might have this method as a protected method in the Figure class, or perhaps as a static method in a new static class, called something like ChessMoves or (Eric's suggestion) Rulebook.
  • In GetRookMoves, the while-loops for rightMove, topMove, leftMove, and downMove are all very similar. See if you can combine these four pieces of code into one.
  • I find the method call WillCollideWithEnemy(rightMove, PieceColor).Item1 to be confusing. Given the name WillCollideWithEnemy, I would expect that method to return a bool, but a bool doesn't have an Item1. Consider doing the following instead:
    • Create a method public Figure GetEnemyAt(boardPosition, pieceColor), which returns null if the square at boardPosition is empty or contains an allied piece.
    • Create a separate method public bool ContainsEnemy(boardPosition, pieceColor), which merely checks if the square contains an enemy or not and returns true or false. (This method could be implemented as a one-liner: return (GetEnemyAt(boardPosition, pieceColor) != null);.)
  • For the while-loops in GetRookMoves, the logic seems a little more complicated than necessary.
    • The startingMoves variable isn't necessary. Remove it, and initialize validMoves as the empty list.
    • The implementation of the while-loops could be something like the following:

BoardPosition destination = CurrentPosition;
while(true)
{
    destination = destination.Move(right: 1, up: 0);
    if (IsOutOfBounds(destination) || WillCollideWithAlly(destination, PieceColor))
    {
        break;
    }
    validMoves.Add(destination);
    if (ContainsEnemy(destination, PieceColor))
    {
        break;
    }
}
  • Consider making all of the members of ImagePaths const instead of static. You should be able to use definitions such as public const string BlackPawnImagePath = assetsPath + @"Black\b-peshka.png";. (Making ImagePaths a static class was a good idea.)
  • Consider making Rochade a static class and turning all of its non-constant properties (including newKingMove) into parameters and/or local variables of the methods.
  • In the PassedTurns class, shouldn't Actions, Positions, and PieceTypes all be lists?
\$\endgroup\$
1
  • \$\begingroup\$ "It would be useful for BoardPosition to have a method public BoardPosition Move(int right, int up) which returns a new BoardPosition with the coordinates altered appropriately." - Good idea. I might use this idea in my own chess program. \$\endgroup\$ Commented Aug 14, 2018 at 0:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.