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 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 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 GetTargetFields(Field[,] fields, Vector location, PieceColor color) { Dictionary targetFields = new Dictionary(); 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 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 GetTargetFields(Field[,] fields, Vector location, PieceColor color, bool onlyAttackFields = false) { Dictionary targetFields = new Dictionary(); 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 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 GetTargetFields(Field[,] fields, Vector location, PieceColor color) { Dictionary targetFields = new Dictionary(); 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 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 GetTargetFields(Field[,] fields, Vector location, PieceColor color, bool onlyAttackFields = true) { Dictionary targetFields = new Dictionary(); 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 GetValidTargetFields(Field[,] fields, Vector location, bool ignoreKingCheck = false, bool testKingDanger = false) { Dictionary 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 GetValidTargetFields(Field[,] fields, Vector location, bool ignoreKingCheck = false, bool testKingDanger = false) // ignoreKingCheck hat keinen Einfluss { return GetTargetFields(fields, location, this.color); } private Dictionary GetTargetFields(Field[,] fields, Vector location, PieceColor color) { Dictionary targetFields = new Dictionary(); #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 }