282 lines
12 KiB
C#
282 lines
12 KiB
C#
using Chess;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Linq;
|
|
using System.Windows;
|
|
using System.Windows.Forms;
|
|
using static Chess.Piece;
|
|
|
|
namespace ChessPanel
|
|
{
|
|
public partial class ChessBoard : Panel
|
|
{
|
|
private BackgroundWorker BGWorker = new BackgroundWorker();
|
|
public Grid fields;
|
|
public List<Piece> pieces;
|
|
|
|
public PieceColor activePlayer;
|
|
private int GRID_SIZE = 8;
|
|
public bool isSaved = true;
|
|
Dictionary<Field, PieceTeam> SelectedPieceTargetSpots = new Dictionary<Field, PieceTeam>();
|
|
//private Vector? selectedField;
|
|
//private Vector? SelectedField
|
|
//{
|
|
// get { return selectedField; }
|
|
// set { selectedField = value; HighlightValidTargetSpots(); }
|
|
//}
|
|
private Field selectedField;
|
|
|
|
private Field SelectedField
|
|
{
|
|
get { return selectedField; }
|
|
set { selectedField = value; HighlightValidTargetSpots(); }
|
|
}
|
|
private bool FieldIsSelected
|
|
{
|
|
get { return selectedField != null; }
|
|
}
|
|
|
|
private void HighlightValidTargetSpots()
|
|
{
|
|
if (FieldIsSelected && selectedField.CurrentPiece != null) // Wenn das neu ausgewählte Feld eine Figur enthält, wird diese ausgewählt
|
|
{
|
|
selectedField.Select();
|
|
}
|
|
ResetValidTargetSpots();
|
|
if (FieldIsSelected)
|
|
{
|
|
if (selectedField.CurrentPiece != null)
|
|
{
|
|
//SelectedPieceTargetSpots = selectedField.CurrentPiece.GetValidTargetFields(fields);
|
|
SelectedPieceTargetSpots = selectedField.CurrentPiece.validTargetSpots;
|
|
if (SelectedPieceTargetSpots == null)
|
|
SelectedPieceTargetSpots = selectedField.CurrentPiece.GetValidTargetFields(fields);
|
|
}
|
|
if (SelectedPieceTargetSpots != null)
|
|
foreach (var TargetSpot in SelectedPieceTargetSpots)
|
|
{
|
|
TargetSpot.Key.Highlight(TargetSpot.Value);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Setzt die Markierungen sowie die Liste der möglichen Zielfelder zurück
|
|
/// </summary>
|
|
private void ResetValidTargetSpots()
|
|
{
|
|
foreach (var validTarget in SelectedPieceTargetSpots)
|
|
{
|
|
validTarget.Key.Deselect();
|
|
}
|
|
SelectedPieceTargetSpots.Clear(); // Markierung der Zielfelder zurücksetzen
|
|
}
|
|
public int GridSize
|
|
{
|
|
get { return GRID_SIZE; }
|
|
set { GRID_SIZE = value; }
|
|
}
|
|
public ChessBoard()
|
|
{
|
|
this.DoubleBuffered = true;
|
|
this.SuspendLayout();
|
|
this.Resize += new System.EventHandler(this.ChessBoard_Resize);
|
|
// this.validTargetSpotCalculator.WorkerReportsProgress = true;// Progress
|
|
BGWorker.WorkerSupportsCancellation = true;
|
|
this.BGWorker.RunWorkerCompleted += ValidTargetSpotCalculator_RunWorkerCompleted;
|
|
this.BGWorker.DoWork += ValidTargetSpotCalculator_DoWork;
|
|
BeginTargetFieldCalculation();
|
|
InitializeGrid();
|
|
InitializePieces();
|
|
activePlayer = PieceColor.White;
|
|
this.ResumeLayout(false);
|
|
}
|
|
|
|
private void ValidTargetSpotCalculator_DoWork(object sender, DoWorkEventArgs e)
|
|
{
|
|
BGWorkerData data = e.Argument as BGWorkerData;
|
|
List<Piece> ActivePlayerPieces = data.pieces.Where(i => i.color == data.color).ToList();
|
|
int total = ActivePlayerPieces.Count;
|
|
int count = 0;
|
|
foreach (var piece in ActivePlayerPieces)
|
|
{
|
|
if (BGWorker.CancellationPending)
|
|
{
|
|
e.Cancel = true;
|
|
return;
|
|
}
|
|
piece.RefreshValidTargetSpots(data.fields);
|
|
// validTargetSpotCalculator.ReportProgress((int)Math.Floor((float)(++count) / (float)total * 100f)); // Progress
|
|
}
|
|
}
|
|
|
|
private void ValidTargetSpotCalculator_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
private void ToggleActivePlayer() => activePlayer = activePlayer == PieceColor.White ? PieceColor.Black : PieceColor.White;
|
|
private void DoPieceMove(Field PieceField, Field newPieceField, bool togglePlayer = true, bool skipValidTargetFieldCalculation = false)
|
|
{
|
|
isSaved = false;
|
|
#region Castling
|
|
if (PieceField.CurrentPiece.type == PieceType.King && Math.Abs(newPieceField.location.X - PieceField.location.X) == 2)
|
|
DoPieceMove(fields[((newPieceField.location.X - PieceField.location.X == -2) ? 0 : 7), PieceField.location.Y], fields[PieceField.location.X + (newPieceField.location.X - PieceField.location.X) / 2, PieceField.location.Y], false /*Dont Toggle Player*/, true); // Move Rook
|
|
#endregion
|
|
#region EnPassant
|
|
foreach (Piece item in pieces.Where(i => i.type == PieceType.Pawn)) // Reset Enpassant Possible states each move
|
|
item.EnPassantPossible = false;
|
|
if (PieceField.CurrentPiece.type == PieceType.Pawn && !PieceField.CurrentPiece.HasMoved)
|
|
PieceField.CurrentPiece.EnPassantPossible = true;
|
|
if (PieceField.CurrentPiece.type == PieceType.Pawn && newPieceField.location.X != PieceField.location.X && newPieceField.IsEmpty)
|
|
fields[newPieceField.location, 0, (PieceField.CurrentPiece.color == PieceColor.White ? 1 : -1)].CurrentPiece = null;
|
|
#endregion
|
|
PieceField.CurrentPiece.Move(newPieceField);
|
|
//PieceField.CurrentPiece.HasMoved = true; // Figur Bereits bewegt Status aktualisieren
|
|
//newPieceField.CurrentPiece = PieceField.CurrentPiece; // Figur an neue Position kopieren
|
|
//PieceField.CurrentPiece = null; // Alte Kopie der Figur löschen
|
|
if (togglePlayer)
|
|
ToggleActivePlayer();
|
|
if (skipValidTargetFieldCalculation) BeginTargetFieldCalculation();
|
|
}
|
|
|
|
class BGWorkerData
|
|
{
|
|
public BGWorkerData(PieceColor color, List<Piece> pieces, Grid fields)
|
|
{
|
|
this.color = color;
|
|
this.pieces = pieces;
|
|
this.fields = fields;
|
|
}
|
|
public PieceColor color;
|
|
public List<Piece> pieces;
|
|
public Grid fields;
|
|
}
|
|
|
|
private void BeginTargetFieldCalculation()
|
|
{
|
|
if (BGWorker.WorkerSupportsCancellation)
|
|
BGWorker.CancelAsync();
|
|
else
|
|
BGWorker.RunWorkerAsync(new BGWorkerData(activePlayer, pieces, fields));
|
|
}
|
|
|
|
private void InitializePieces()
|
|
{
|
|
pieces = new List<Piece>
|
|
{
|
|
new Rook(PieceColor.Black, new Vector(0, 0), fields),
|
|
new Rook(PieceColor.Black, new Vector(7, 0), fields),
|
|
new Rook(PieceColor.White, new Vector(0, 7), fields),
|
|
new Rook(PieceColor.White, new Vector(7, 7), fields),
|
|
|
|
new Knight(PieceColor.Black, new Vector(1, 0), fields),
|
|
new Knight(PieceColor.Black, new Vector(6, 0), fields),
|
|
new Knight(PieceColor.White, new Vector(1, 7), fields),
|
|
new Knight(PieceColor.White, new Vector(6, 7), fields),
|
|
|
|
new Bishop(PieceColor.Black, new Vector(2, 0), fields),
|
|
new Bishop(PieceColor.Black, new Vector(5, 0), fields),
|
|
new Bishop(PieceColor.White, new Vector(2, 7), fields),
|
|
new Bishop(PieceColor.White, new Vector(5, 7),fields),
|
|
new King(PieceColor.Black, new Vector(4, 0), fields),
|
|
new Queen(PieceColor.Black, new Vector(3, 0), fields),
|
|
|
|
new Queen(PieceColor.White, new Vector(3, 7), fields),
|
|
new King(PieceColor.White, new Vector(4, 7), fields)
|
|
};
|
|
|
|
for (int x = 0; x < 8; x++)
|
|
{
|
|
pieces.Add(new Pawn(PieceColor.Black, new Vector(x, 1), fields));
|
|
pieces.Add(new Pawn(PieceColor.White, new Vector(x, 6), fields));
|
|
}
|
|
|
|
|
|
foreach (Field field in fields)
|
|
{
|
|
field.RefreshPiece();
|
|
}
|
|
}
|
|
private void InitializeGrid()
|
|
{
|
|
this.fields = new Grid(GRID_SIZE);
|
|
int subPanelEdgeLength = Math.Min(this.Size.Width, this.Size.Height) / GRID_SIZE;
|
|
System.Drawing.Size subPanelSize = new System.Drawing.Size(subPanelEdgeLength, subPanelEdgeLength);
|
|
for (int x = 0; x < this.GRID_SIZE; x++)
|
|
{
|
|
for (int y = 0; y < this.GRID_SIZE; y++)
|
|
{
|
|
Field field = new Field(x, y)
|
|
{
|
|
Size = subPanelSize,
|
|
Location = new System.Drawing.Point(x * subPanelSize.Width, y * subPanelSize.Height)
|
|
};
|
|
field.FieldClick += FieldClicked;
|
|
fields[x, y] = field;
|
|
this.Controls.Add(fields[x, y]);
|
|
}
|
|
}
|
|
}
|
|
private void FieldClicked(Field sender)
|
|
{
|
|
this.SuspendLayout();
|
|
if (FieldIsSelected && SelectedPieceTargetSpots.ContainsKey(sender)) // Ein erlaubtes Zielfeld wurde angeklickt
|
|
{
|
|
DoPieceMove(SelectedField, sender); // Bewege Figur
|
|
ResetSelectedField(); // Auswahl zurücksetzen
|
|
}
|
|
else
|
|
{
|
|
if (SelectedField == sender) // Erneutes Anklicken des Auswahlfeldes
|
|
ResetSelectedField(); // Auswahl zurücksetzen
|
|
else // Tritt ein, wenn ein Feld angeklickt wurde, dass nicht das Auswahlfeld ist
|
|
{
|
|
if (FieldIsSelected) // Wenn ein Feld ausgewählt ist wird die Auswahl gelöscht falls nicht das Auswahlfeld angeklickt wurde
|
|
ResetSelectedField(); // Auswahl zurücksetzen
|
|
if (!sender.IsEmpty && sender.CurrentPiece.color == activePlayer) // Feld wird nur ausgewählt, wenn die Farbe der Figur mit der des aktiven Spielers übereinstimmt
|
|
SelectedField = sender; // Kein Feld ist ausgewählt: Angeklicktes Feld auswählen (!) AKTUALISIERT AUTOMATISCH DIE MARKIERUNGEN
|
|
}
|
|
}
|
|
this.ResumeLayout(false);
|
|
}
|
|
/// <summary>
|
|
/// Löscht die Auswahl des aktuell ausgewählten Feldes
|
|
/// </summary>
|
|
private void ResetSelectedField()
|
|
{
|
|
SelectedField.Deselect(); // Auswahl zurücksetzen
|
|
SelectedField = null; // Erlaubte Zielfelder zurücksetzen
|
|
}
|
|
#region Helper Can be deleted
|
|
static readonly string[] Columns = new[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ", "AK", "AL", "AM", "AN", "AO", "AP", "AQ", "AR", "AS", "AT", "AU", "AV", "AW", "AX", "AY", "AZ", "BA", "BB", "BC", "BD", "BE", "BF", "BG", "BH" };
|
|
public static string IndexToColumn(int index)
|
|
{
|
|
if (index <= 0)
|
|
throw new IndexOutOfRangeException("index must be a positive number");
|
|
|
|
return Columns[index - 1];
|
|
}
|
|
#endregion
|
|
private void ChessBoard_Resize(object sender, EventArgs e)
|
|
{
|
|
RefreshSize();
|
|
}
|
|
private void RefreshSize()
|
|
{
|
|
this.SuspendLayout();
|
|
int subPanelEdgeLength = Math.Min(this.Size.Width, this.Size.Height) / GRID_SIZE;
|
|
System.Drawing.Size subPanelSize = new System.Drawing.Size(subPanelEdgeLength, subPanelEdgeLength);
|
|
for (int x = 0; x < this.GRID_SIZE; x++)
|
|
{
|
|
for (int y = 0; y < this.GRID_SIZE; y++)
|
|
{
|
|
fields[x, y].Size = subPanelSize;
|
|
fields[x, y].Location = new System.Drawing.Point(x * subPanelSize.Width, y * subPanelSize.Height);
|
|
}
|
|
}
|
|
this.ResumeLayout(false);
|
|
}
|
|
}
|
|
}
|