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;
}
}
}
1 Answer 1
- Some of the terminology you're using is unusual. I would say
Piece
orMan
instead ofFigure
, and "castling" instead of "Rochade".GetValidTurns
should probably be calledGetValidMoves
. - As Eric Lippert suggests on your other question, you should probably create a struct called
BoardPosition
which contains a row and a column asint
s.- 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 methodpublic BoardPosition Move(int right, int up)
which returns a newBoardPosition
with the coordinates altered appropriately.
- The code for
- If you wanted, you could make
GetValidTurns
onQueenPiece
just a single line:return GetRookMoves().Concat(GetBishopMoves()).ToList();
- The methods
GetValidTurns
onRookPiece
andGetRookMoves
onQueenPiece
are very similar. Consider replacing these two methods with a singleGetRookMoves
method. You might have this method as a protected method in theFigure
class, or perhaps as a static method in a new static class, called something likeChessMoves
or (Eric's suggestion)Rulebook
. - In
GetRookMoves
, the while-loops forrightMove
,topMove
,leftMove
, anddownMove
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 nameWillCollideWithEnemy
, I would expect that method to return abool
, but abool
doesn't have anItem1
. Consider doing the following instead:- Create a method
public Figure GetEnemyAt(boardPosition, pieceColor)
, which returnsnull
if the square atboardPosition
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 returnstrue
orfalse
. (This method could be implemented as a one-liner:return (GetEnemyAt(boardPosition, pieceColor) != null);
.)
- Create a method
- For the while-loops in
GetRookMoves
, the logic seems a little more complicated than necessary.- The
startingMoves
variable isn't necessary. Remove it, and initializevalidMoves
as the empty list. - The implementation of the while-loops could be something like the following:
- The
—
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 ofstatic
. You should be able to use definitions such aspublic const string BlackPawnImagePath = assetsPath + @"Black\b-peshka.png";
. (MakingImagePaths
a static class was a good idea.) - Consider making
Rochade
a static class and turning all of its non-constant properties (includingnewKingMove
) into parameters and/or local variables of the methods. - In the
PassedTurns
class, shouldn'tActions
,Positions
, andPieceTypes
all be lists?
-
\$\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\$RedDragonWebDesign– RedDragonWebDesign2018年08月14日 00:58:26 +00:00Commented Aug 14, 2018 at 0:58
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\$