chess-board/ChessPanel/ChessBoard.cs

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);
}
}
}