461 lines
22 KiB
C#
461 lines
22 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Drawing;
|
|
using ChessPanel;
|
|
using System.Linq;
|
|
using System.Windows;
|
|
|
|
namespace Chess
|
|
{
|
|
public abstract class Piece
|
|
{
|
|
public enum PieceColor { White, Black };
|
|
public enum PieceTeam { Enemy, Ally };
|
|
public enum PieceType { King, Queen, Bishop, Rook, Knight, Pawn };
|
|
public PieceColor color;
|
|
public PieceType type;
|
|
public Image image;
|
|
public bool HasMoved = false;
|
|
public bool EnPassantPossible = false; // Only in Pawn Class. Signs that this Piece has virtually not jumped two pieces, but one
|
|
internal static bool IsEndangeredLocationForPiece(Field[,] fields, Vector pieceLocation, Vector testLocation, PieceColor color)
|
|
{
|
|
bool returnValue = false;
|
|
Piece p = fields[(int)pieceLocation.X, (int)pieceLocation.Y].currentPiece;
|
|
fields[(int)pieceLocation.X, (int)pieceLocation.Y].currentPiece = null;
|
|
foreach (var field in fields)
|
|
{
|
|
if (field.currentPiece != null) if (field.currentPiece.color != color) if (field.currentPiece.GetValidTargetFields(fields, field.location, true).ContainsKey(testLocation))
|
|
{
|
|
returnValue = true;
|
|
break;
|
|
}
|
|
}
|
|
fields[(int)pieceLocation.X, (int)pieceLocation.Y].currentPiece = p;
|
|
return returnValue;
|
|
}
|
|
internal static bool MoveWillEndangerKing(Field[,] fields, Vector pieceLocation, Vector pieceMovedLocation, PieceColor color) // This does not test if it is a valid move spot
|
|
{
|
|
bool returnValue = false;
|
|
Piece p1 = fields[(int)pieceLocation.X, (int)pieceLocation.Y].currentPiece;
|
|
Piece p2 = fields[(int)pieceMovedLocation.X, (int)pieceMovedLocation.Y].currentPiece;
|
|
fields[(int)pieceLocation.X, (int)pieceLocation.Y].currentPiece = null;
|
|
fields[(int)pieceMovedLocation.X, (int)pieceMovedLocation.Y].currentPiece = p1;
|
|
returnValue = KingIsEndangered(fields, color);
|
|
fields[(int)pieceLocation.X, (int)pieceLocation.Y].currentPiece = p1;
|
|
fields[(int)pieceMovedLocation.X, (int)pieceMovedLocation.Y].currentPiece = p2;
|
|
return returnValue;
|
|
}
|
|
|
|
private static bool KingIsEndangered(Field[,] fields, PieceColor color)
|
|
{
|
|
Vector kingLocation = GetKingLocation(fields, color);
|
|
foreach (var field in fields)
|
|
{
|
|
if (field.currentPiece == null || field.currentPiece.color != color)
|
|
continue;
|
|
if (field.currentPiece.GetValidTargetFields(fields, field.location, testKingDanger: true).ContainsKey(kingLocation))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static Vector GetKingLocation(Field[,] fields, PieceColor color)
|
|
{
|
|
foreach (var field in fields)
|
|
if (!field.IsEmpty && field.currentPiece.type == PieceType.King && field.currentPiece.color == color)
|
|
return field.location;
|
|
throw new Exception("King not found!");
|
|
}
|
|
|
|
internal abstract Dictionary<Vector, PieceTeam> GetValidTargetFields(Field[,] fields, Vector currentLocation, bool onlyAttackFields = false, bool testKingDanger = false);
|
|
}
|
|
public class Rook : Piece
|
|
{
|
|
public Rook(PieceColor color)
|
|
{
|
|
type = (PieceType)Enum.Parse(typeof(PieceType), this.GetType().Name);
|
|
this.color = color;
|
|
this.image = (Image)ChessPanel.Properties.Resources.ResourceManager.GetObject($"{this.type.ToString()}{this.color.ToString()}");
|
|
}
|
|
|
|
internal override Dictionary<Vector, PieceTeam> GetValidTargetFields(Field[,] fields, Vector location, bool ignoreKingCheck = false, bool testKingDanger = false)
|
|
{
|
|
var targetFields = GetTargetFields(fields, location, this.color);
|
|
/*if (!testKingDanger)
|
|
foreach (var item in targetFields)
|
|
if (MoveWillEndangerKing(fields, location, item.Key, this.color))
|
|
targetFields.Remove(item.Key);*/
|
|
return targetFields;
|
|
}
|
|
|
|
internal static Dictionary<Vector, PieceTeam> GetTargetFields(Field[,] fields, Vector location, PieceColor color)
|
|
{
|
|
Dictionary<Vector, PieceTeam> targetFields = new Dictionary<Vector, PieceTeam>();
|
|
|
|
for (int x = (int)location.X - 1; x >= 0; x--) // nach Links
|
|
{
|
|
if (fields[x, (int)location.Y].IsEmpty)
|
|
{
|
|
targetFields.Add(new Vector(x, (int)location.Y), PieceTeam.Ally);
|
|
}
|
|
else
|
|
{
|
|
if (fields[x, (int)location.Y].currentPiece.color != color)
|
|
targetFields.Add(new Vector(x, (int)location.Y), PieceTeam.Enemy);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
for (int x = (int)location.X + 1; x <= 7; x++) // nach Rechts
|
|
{
|
|
if (fields[x, (int)location.Y].IsEmpty)
|
|
{
|
|
targetFields.Add(new Vector(x, (int)location.Y), PieceTeam.Ally);
|
|
}
|
|
else
|
|
{
|
|
if (fields[x, (int)location.Y].currentPiece.color != color)
|
|
targetFields.Add(new Vector(x, (int)location.Y), PieceTeam.Enemy);
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (int y = (int)location.Y - 1; y >= 0; y--) // nach Unten
|
|
{
|
|
if (fields[(int)(int)location.X, y].IsEmpty)
|
|
{
|
|
targetFields.Add(new Vector((int)location.X, y), PieceTeam.Ally);
|
|
}
|
|
else
|
|
{
|
|
if (fields[(int)(int)location.X, y].currentPiece.color != color)
|
|
targetFields.Add(new Vector((int)location.X, y), PieceTeam.Enemy);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
for (int y = (int)location.Y + 1; y <= 7; y++) // nach Oben
|
|
{
|
|
if (fields[(int)(int)location.X, y].IsEmpty)
|
|
{
|
|
targetFields.Add(new Vector((int)location.X, y), PieceTeam.Ally);
|
|
}
|
|
else
|
|
{
|
|
if (fields[(int)(int)location.X, y].currentPiece.color != color)
|
|
targetFields.Add(new Vector((int)location.X, y), PieceTeam.Enemy);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return targetFields;
|
|
}
|
|
} // FINALIZED
|
|
public class Pawn : Piece
|
|
{
|
|
public Pawn(PieceColor color)
|
|
{
|
|
type = (PieceType)Enum.Parse(typeof(PieceType), this.GetType().Name);
|
|
this.color = color;
|
|
this.image = (Image)ChessPanel.Properties.Resources.ResourceManager.GetObject($"{this.type.ToString()}{this.color.ToString()}");
|
|
}
|
|
|
|
internal override Dictionary<Vector, PieceTeam> GetValidTargetFields(Field[,] fields, Vector location, bool onlyAttackFields = false, bool testKingDanger = false)
|
|
{
|
|
var targetFields = GetTargetFields(fields, location, this.color, onlyAttackFields);
|
|
/*if (!testKingDanger)
|
|
foreach (var item in targetFields)
|
|
if (MoveWillEndangerKing(fields, location, item.Key, this.color))
|
|
targetFields.Remove(item.Key);*/
|
|
return targetFields;
|
|
}
|
|
|
|
private Dictionary<Vector, PieceTeam> GetTargetFields(Field[,] fields, Vector location, PieceColor color, bool onlyAttackFields = false)
|
|
{
|
|
Dictionary<Vector, PieceTeam> targetFields = new Dictionary<Vector, PieceTeam>();
|
|
int direction = this.color == PieceColor.White ? -1 : 1;
|
|
#region EnPassant
|
|
if (location.Y == (this.color == PieceColor.White ? 3 : 4))
|
|
for (int x = -1; x < 2; x += 2)
|
|
if (location.X + x <= 7 && location.X + x >= 0)
|
|
if (fields[(int)location.X + x, (int)location.Y].currentPiece != null)
|
|
if (fields[(int)location.X + x, (int)location.Y].currentPiece.type == PieceType.Pawn)
|
|
if (fields[(int)location.X + x, (int)location.Y].currentPiece.color != this.color)
|
|
if (fields[(int)location.X + x, (int)location.Y].currentPiece.EnPassantPossible)
|
|
targetFields.Add(new Vector(location.X + x, location.Y + direction), PieceTeam.Enemy);
|
|
#endregion
|
|
#region Movement
|
|
if (!onlyAttackFields)
|
|
for (int y = 1; y < 1 + (HasMoved ? 1 : 2); y++)
|
|
{
|
|
if (location.Y + (direction * y) > 7 || location.Y + (direction * y) < 0)
|
|
break;
|
|
if (fields[(int)location.X, (int)location.Y + (direction * y)].IsEmpty)
|
|
targetFields.Add(new Vector(location.X, (int)location.Y + (direction * y)), PieceTeam.Ally);
|
|
else
|
|
break;
|
|
}
|
|
#endregion
|
|
#region Attack
|
|
for (int x = -1; x < 2; x += 2)
|
|
{
|
|
if (location.Y + (direction) > 7 || location.Y + (direction) < 0 || location.X + x > 7 || location.X + x < 0)
|
|
continue;
|
|
if (onlyAttackFields || (fields[(int)location.X + x, (int)location.Y + (direction)].currentPiece != null && fields[(int)location.X + x, (int)location.Y + (direction)].currentPiece.color != this.color))
|
|
{
|
|
targetFields.Add(new Vector((int)location.X + x, (int)location.Y + (direction)), PieceTeam.Enemy);
|
|
}
|
|
}
|
|
#endregion
|
|
return targetFields;
|
|
}
|
|
} // EN-PASSANT MISSING
|
|
public class Knight : Piece
|
|
{
|
|
public Knight(PieceColor color)
|
|
{
|
|
type = (PieceType)Enum.Parse(typeof(PieceType), this.GetType().Name);
|
|
this.color = color;
|
|
this.image = (Image)ChessPanel.Properties.Resources.ResourceManager.GetObject($"{this.type.ToString()}{this.color.ToString()}");
|
|
}
|
|
|
|
internal override Dictionary<Vector, PieceTeam> GetValidTargetFields(Field[,] fields, Vector location, bool ignoreKingCheck = false, bool testKingDanger = false)
|
|
{
|
|
var targetFields = GetTargetFields(fields, location, this.color);
|
|
/* if (!testKingDanger)
|
|
foreach (var item in targetFields)
|
|
if (MoveWillEndangerKing(fields, location, item.Key, this.color))
|
|
targetFields.Remove(item.Key);*/
|
|
return targetFields;
|
|
}
|
|
|
|
private Dictionary<Vector, PieceTeam> GetTargetFields(Field[,] fields, Vector location, PieceColor color)
|
|
{
|
|
Dictionary<Vector, PieceTeam> targetFields = new Dictionary<Vector, PieceTeam>();
|
|
|
|
for (int a = -1; a < 2; a += 2)
|
|
{
|
|
for (int b = -2; b < 3; b += 4)
|
|
{
|
|
if (!(a + (int)location.X > 7 || b + (int)location.Y < 0 || a + (int)location.X < 0 || b + (int)location.Y > 7))
|
|
{
|
|
if (fields[a + (int)location.X, b + (int)location.Y].IsEmpty)
|
|
{
|
|
targetFields.Add(new Vector(a + (int)location.X, b + (int)location.Y), PieceTeam.Ally);
|
|
}
|
|
else
|
|
{
|
|
if (fields[a + (int)location.X, b + (int)location.Y].currentPiece.color != color)
|
|
targetFields.Add(new Vector(a + (int)location.X, b + (int)location.Y), PieceTeam.Enemy);
|
|
}
|
|
}
|
|
if (!(b + (int)location.X > 7 || a + (int)location.Y < 0 || b + (int)location.X < 0 || a + (int)location.Y > 7))
|
|
{
|
|
if (fields[b + (int)location.X, a + (int)location.Y].IsEmpty)
|
|
{
|
|
targetFields.Add(new Vector(b + (int)location.X, a + (int)location.Y), PieceTeam.Ally);
|
|
}
|
|
else
|
|
{
|
|
if (fields[b + (int)location.X, a + (int)location.Y].currentPiece.color != color)
|
|
targetFields.Add(new Vector(b + (int)location.X, a + (int)location.Y), PieceTeam.Enemy);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return targetFields;
|
|
}
|
|
} // FINALIZED
|
|
public class Bishop : Piece
|
|
{
|
|
public Bishop(PieceColor color)
|
|
{
|
|
type = (PieceType)Enum.Parse(typeof(PieceType), this.GetType().Name);
|
|
this.color = color;
|
|
this.image = (Image)ChessPanel.Properties.Resources.ResourceManager.GetObject($"{this.type.ToString()}{this.color.ToString()}");
|
|
}
|
|
|
|
internal override Dictionary<Vector, PieceTeam> GetValidTargetFields(Field[,] fields, Vector location, bool onlyAttackFields = false, bool testKingDanger = false)
|
|
{
|
|
var targetFields = GetTargetFields(fields, location, this.color, onlyAttackFields);
|
|
/* if (!testKingDanger)
|
|
foreach (var item in targetFields)
|
|
if (MoveWillEndangerKing(fields, location, item.Key, this.color))
|
|
targetFields.Remove(item.Key);*/
|
|
return targetFields;
|
|
}
|
|
internal static Dictionary<Vector, PieceTeam> GetTargetFields(Field[,] fields, Vector location, PieceColor color, bool onlyAttackFields = true)
|
|
{
|
|
Dictionary<Vector, PieceTeam> targetFields = new Dictionary<Vector, PieceTeam>();
|
|
|
|
for (int xy = 1; xy <= 7; xy++) // nach RechtsOben
|
|
{
|
|
if (location.X + xy > 7 || (int)location.Y + xy > 7)
|
|
break;
|
|
if (fields[xy + (int)location.X, xy + (int)location.Y].IsEmpty)
|
|
{
|
|
targetFields.Add(new Vector(xy + (int)location.X, xy + (int)location.Y), PieceTeam.Ally);
|
|
}
|
|
else
|
|
{
|
|
if (fields[xy + (int)location.X, xy + (int)location.Y].currentPiece.color != color)
|
|
targetFields.Add(new Vector(xy + (int)location.X, xy + (int)location.Y), PieceTeam.Enemy);
|
|
break;
|
|
}
|
|
}
|
|
for (int xy = 1; xy <= 7; xy++) // nach LinksOben
|
|
{
|
|
if (location.X - xy < 0 || (int)location.Y + xy > 7)
|
|
break;
|
|
if (fields[(int)location.X - xy, (int)location.Y + xy].IsEmpty)
|
|
{
|
|
targetFields.Add(new Vector(location.X - xy, (int)location.Y + xy), PieceTeam.Ally);
|
|
}
|
|
else
|
|
{
|
|
if (fields[(int)location.X - xy, (int)location.Y + xy].currentPiece.color != color)
|
|
targetFields.Add(new Vector(location.X - xy, (int)location.Y + xy), PieceTeam.Enemy);
|
|
break;
|
|
}
|
|
}
|
|
for (int xy = 1; xy <= 7; xy++) // nach RechtsUnten
|
|
{
|
|
if (location.X + xy > 7 || (int)location.Y - xy < 0)
|
|
break;
|
|
if (fields[xy + (int)location.X, (int)location.Y - xy].IsEmpty)
|
|
{
|
|
targetFields.Add(new Vector(xy + (int)location.X, (int)location.Y - xy), PieceTeam.Ally);
|
|
}
|
|
else
|
|
{
|
|
if (fields[xy + (int)location.X, (int)location.Y - xy].currentPiece.color != color)
|
|
targetFields.Add(new Vector(xy + (int)location.X, (int)location.Y - xy), PieceTeam.Enemy);
|
|
break;
|
|
}
|
|
}
|
|
for (int xy = 1; xy <= 7; xy++) // nach LinksUnten
|
|
{
|
|
if (location.X - xy < 0 || (int)location.Y - xy < 0)
|
|
break;
|
|
if (fields[(int)location.X - xy, (int)location.Y - xy].IsEmpty)
|
|
{
|
|
targetFields.Add(new Vector(location.X - xy, (int)location.Y - xy), PieceTeam.Ally);
|
|
}
|
|
else
|
|
{
|
|
if (fields[(int)location.X - xy, (int)location.Y - xy].currentPiece.color != color)
|
|
targetFields.Add(new Vector(location.X - xy, (int)location.Y - xy), PieceTeam.Enemy);
|
|
break;
|
|
}
|
|
}
|
|
return targetFields;
|
|
}
|
|
} // FINALIZED
|
|
public class Queen : Piece
|
|
{
|
|
public Queen(PieceColor color)
|
|
{
|
|
type = (PieceType)Enum.Parse(typeof(PieceType), this.GetType().Name);
|
|
this.color = color;
|
|
this.image = (Image)ChessPanel.Properties.Resources.ResourceManager.GetObject($"{this.type.ToString()}{this.color.ToString()}");
|
|
}
|
|
|
|
internal override Dictionary<Vector, PieceTeam> GetValidTargetFields(Field[,] fields, Vector location, bool ignoreKingCheck = false, bool testKingDanger = false)
|
|
{
|
|
Dictionary<Vector, PieceTeam> targetFields = Rook.GetTargetFields(fields, location, this.color);
|
|
targetFields = targetFields.Concat(Bishop.GetTargetFields(fields, location, this.color)
|
|
.Where(kvp => !targetFields.ContainsKey(kvp.Key)))
|
|
.OrderBy(c => c.Value)
|
|
.ToDictionary(c => c.Key, c => c.Value);
|
|
/*if (!testKingDanger)
|
|
foreach (var item in targetFields)
|
|
if (MoveWillEndangerKing(fields, location, item.Key, this.color))
|
|
targetFields.Remove(item.Key);*/
|
|
return targetFields;
|
|
}
|
|
} // FINALIZED
|
|
public class King : Piece
|
|
{
|
|
public King(PieceColor color)
|
|
{
|
|
type = (PieceType)Enum.Parse(typeof(PieceType), this.GetType().Name);
|
|
this.color = color;
|
|
this.image = (Image)ChessPanel.Properties.Resources.ResourceManager.GetObject($"{this.type.ToString()}{this.color.ToString()}");
|
|
}
|
|
|
|
internal override Dictionary<Vector, PieceTeam> GetValidTargetFields(Field[,] fields, Vector location, bool ignoreKingCheck = false, bool testKingDanger = false) // ignoreKingCheck hat keinen Einfluss
|
|
{
|
|
return GetTargetFields(fields, location, this.color);
|
|
}
|
|
|
|
private Dictionary<Vector, PieceTeam> GetTargetFields(Field[,] fields, Vector location, PieceColor color)
|
|
{
|
|
Dictionary<Vector, PieceTeam> targetFields = new Dictionary<Vector, PieceTeam>();
|
|
#region Castling
|
|
if (!this.HasMoved) // Only Castle if King did not move
|
|
foreach (var item in fields)
|
|
{
|
|
var itemLocation = item.location;
|
|
// Sucht nach Ally Turm und prüft, ob er sich schon bewegt hat
|
|
if (item.currentPiece != null && item.currentPiece.type == PieceType.Rook && !item.currentPiece.HasMoved && item.currentPiece.color == this.color)
|
|
{
|
|
if (itemLocation.X == 0 || itemLocation.X == 7)
|
|
{
|
|
bool castling = true;
|
|
for (int x = (itemLocation.X == 0 ? 1 : 5); (itemLocation.X == 0 ? x < 4 : x < 7); x++)
|
|
{
|
|
if (!fields[x, (int)location.Y].IsEmpty)
|
|
{
|
|
castling = false;
|
|
break;
|
|
}
|
|
}
|
|
if (castling) // Only Check endangered Fields if castling is generally possible
|
|
{
|
|
for (int x = (itemLocation.X == 0 ? 2 : 4); x < (itemLocation.X == 0 ? 5 : 7); x++) // König steht im Schach oder überschreitet bedrohtes Feld
|
|
{
|
|
if (IsEndangeredLocationForPiece(fields, location, new Vector(x, location.Y), color))
|
|
{
|
|
castling = false;
|
|
break;
|
|
}
|
|
}
|
|
if (castling)
|
|
{
|
|
targetFields.Add(new Vector((itemLocation.X == 0 ? 2 : 6), itemLocation.Y), PieceTeam.Ally);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
#region Movement: 1 in every direction
|
|
for (int x = -1; x < 2; x++)
|
|
{
|
|
for (int y = -1; y < 2; y++)
|
|
{
|
|
if ((x == 0 && y == 0) || location.X + x > 7 || location.Y + y > 7 || location.X + x < 0 || location.Y + y < 0)
|
|
continue;
|
|
if (!IsEndangeredLocationForPiece(fields, location, new Vector(location.X + x, location.Y + y), color))
|
|
if (fields[(int)location.X + x, (int)location.Y + y].IsEmpty)
|
|
{
|
|
targetFields.Add(new Vector(location.X + x, (int)location.Y + y), PieceTeam.Ally);
|
|
}
|
|
else
|
|
{
|
|
if (fields[(int)location.X + x, (int)location.Y + y].currentPiece.color != color)
|
|
targetFields.Add(new Vector(location.X + x, (int)location.Y + y), PieceTeam.Enemy);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
return targetFields;
|
|
}
|
|
} // CHECKMATE/CHECK-TEST MISSING
|
|
} |