diff --git a/.gitignore b/.gitignore index 3c4efe2..8a30d25 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,10 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore # User-specific files +*.rsuser *.suo *.user *.userosscache @@ -10,6 +13,9 @@ # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs +# Mono auto generated files +mono_crash.* + # Build results [Dd]ebug/ [Dd]ebugPublic/ @@ -17,42 +23,62 @@ [Rr]eleases/ x64/ x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ +[Ll]ogs/ -# Visual Studio 2015 cache/options directory +# Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ +# Visual Studio 2017 auto generated files +Generated\ Files/ + # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* -# NUNIT +# NUnit *.VisualState.xml TestResult.xml +nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c -# DNX +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core project.lock.json project.fragment.lock.json artifacts/ +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio *_i.c *_p.c -*_i.h +*_h.h *.ilk *.meta *.obj +*.iobj *.pch *.pdb +*.ipdb *.pgc *.pgd *.rsp @@ -62,7 +88,9 @@ artifacts/ *.tlh *.tmp *.tmp_proj +*_wpftmp.csproj *.log +*.tlog *.vspscc *.vssscc .builds @@ -90,6 +118,9 @@ ipch/ *.vspx *.sap +# Visual Studio Trace Files +*.e2e + # TFS 2012 Local Workspace $tf/ @@ -101,15 +132,25 @@ _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user -# JustCode is a .NET coding add-in -.JustCode - # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + # NCrunch _NCrunch_* .*crunch*.local.xml @@ -141,9 +182,9 @@ publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings +# Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted -#*.pubxml +*.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to @@ -153,13 +194,15 @@ PublishScripts/ # NuGet Packages *.nupkg +# NuGet Symbol Packages +*.snupkg # The packages folder can be ignored because of Package Restore -**/packages/* +**/[Pp]ackages/* # except build/, which is used as an MSBuild target. -!**/packages/build/ +!**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config -# NuGet v3's project.json files produces more ignoreable files +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets @@ -176,12 +219,15 @@ AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt +*.appx +*.appxbundle +*.appxupload # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache -!*.[Cc]ache/ +!?*.[Cc]ache/ # Others ClientBin/ @@ -192,9 +238,12 @@ ClientBin/ *.jfm *.pfx *.publishsettings -node_modules/ orleans.codegen.cs +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ @@ -209,15 +258,22 @@ _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak # SQL Server files *.mdf *.ldf +*.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ @@ -227,6 +283,7 @@ FakesAssemblies/ # Node.js Tools for Visual Studio .ntvs_analysis.dat +node_modules/ # Visual Studio 6 build log *.plg @@ -234,6 +291,20 @@ FakesAssemblies/ # Visual Studio 6 workspace options file *.opt +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts @@ -249,13 +320,79 @@ paket-files/ # FAKE - F# Make .fake/ -# JetBrains Rider -.idea/ -*.sln.iml - -# CodeRush -.cr/ +# CodeRush personal settings +.cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ -*.pyc \ No newline at end of file +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml diff --git a/ChessPanel/Chess.csproj b/ChessPanel/Chess.csproj index 6c20071..ba47077 100644 --- a/ChessPanel/Chess.csproj +++ b/ChessPanel/Chess.csproj @@ -47,6 +47,7 @@ + Component @@ -57,13 +58,18 @@ Component + + + Form MainForm.cs - + + + @@ -71,6 +77,10 @@ True Resources.resx + + + ChessGame.cs + MainForm.cs @@ -78,7 +88,6 @@ PublicResXFileCodeGenerator Resources.Designer.cs - diff --git a/ChessPanel/ChessBoard.cs b/ChessPanel/ChessBoard.cs index 8661f02..7c4dd38 100644 --- a/ChessPanel/ChessBoard.cs +++ b/ChessPanel/ChessBoard.cs @@ -1,6 +1,8 @@ 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; @@ -9,34 +11,53 @@ namespace ChessPanel { public partial class ChessBoard : Panel { - public Field[,] fields; + private BackgroundWorker BGWorker = new BackgroundWorker(); + public Grid fields; + public List pieces; + public PieceColor activePlayer; - private int gridSize = 8; + private int GRID_SIZE = 8; public bool isSaved = true; - Dictionary validTargetSpots = new Dictionary(); - private Vector? selectedField; - private Vector? SelectedField + Dictionary SelectedPieceTargetSpots = new Dictionary(); + //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 (selectedField.HasValue && fields[(int)selectedField.Value.X, (int)selectedField.Value.Y].CurrentPiece != null) // Wenn das neu ausgewählte Feld eine Figur enthält, wird diese ausgewählt + if (FieldIsSelected && selectedField.CurrentPiece != null) // Wenn das neu ausgewählte Feld eine Figur enthält, wird diese ausgewählt { - fields[(int)selectedField.Value.X, (int)selectedField.Value.Y].Select(); + selectedField.Select(); } ResetValidTargetSpots(); - if (selectedField.HasValue) + if (FieldIsSelected) { - if (fields[(int)selectedField.Value.X, (int)selectedField.Value.Y].CurrentPiece != null) + if (selectedField.CurrentPiece != null) { - validTargetSpots = fields[(int)selectedField.Value.X, (int)selectedField.Value.Y].CurrentPiece.GetValidTargetFields(fields, new Vector(selectedField.Value.X, selectedField.Value.Y)); - } - foreach (var item in validTargetSpots) - { - fields[(int)item.Key.X, (int)item.Key.Y].Highlight(item.Value); + //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); + } } } /// @@ -44,119 +65,177 @@ namespace ChessPanel /// private void ResetValidTargetSpots() { - foreach (var item in validTargetSpots) + foreach (var validTarget in SelectedPieceTargetSpots) { - fields[(int)item.Key.X, (int)item.Key.Y].Deselect(); + validTarget.Key.Deselect(); } - validTargetSpots.Clear(); // Markierung der Zielfelder zurücksetzen + SelectedPieceTargetSpots.Clear(); // Markierung der Zielfelder zurücksetzen } public int GridSize { - get { return gridSize; } - set { gridSize = value; } + 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 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(Vector location, Vector newLocation, bool togglePlayer = true) + private void DoPieceMove(Field PieceField, Field newPieceField, bool togglePlayer = true, bool skipValidTargetFieldCalculation = false) { isSaved = false; #region Castling - if (fields[(int)location.X, (int)location.Y].CurrentPiece.type == PieceType.King && Math.Abs(newLocation.X - location.X) == 2) - DoPieceMove(new Vector(((newLocation.X - location.X == -2) ? 0 : 7), location.Y), new Vector(location.X + (newLocation.X - location.X) / 2, location.Y), false /*Dont Toggle Player*/); // Move Rook + 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 (var item in fields) // Reset Enpassant Possible states each move - { - if (item.CurrentPiece != null) - if (item.CurrentPiece.type == PieceType.Pawn) - { - item.CurrentPiece.EnPassantPossible = false; - } - } - if (fields[(int)location.X, (int)location.Y].CurrentPiece.type == PieceType.Pawn && !fields[(int)location.X, (int)location.Y].CurrentPiece.HasMoved) - fields[(int)location.X, (int)location.Y].CurrentPiece.EnPassantPossible = true; - if (fields[(int)location.X, (int)location.Y].CurrentPiece.type == PieceType.Pawn && newLocation.X != location.X && fields[(int)newLocation.X, (int)newLocation.Y].IsEmpty) - fields[(int)newLocation.X, (int)newLocation.Y + (fields[(int)location.X, (int)location.Y].CurrentPiece.color == PieceColor.White ? 1 : -1)].CurrentPiece = null; + 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 - fields[(int)location.X, (int)location.Y].CurrentPiece.HasMoved = true; // Figur Bereits bewegt Status aktualisieren - fields[(int)newLocation.X, (int)newLocation.Y].CurrentPiece = fields[(int)location.X, (int)location.Y].CurrentPiece; // Figur an neue Position kopieren - fields[(int)location.X, (int)location.Y].CurrentPiece = null; // Alte Kopie der Figur löschen + 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 pieces, Grid fields) + { + this.color = color; + this.pieces = pieces; + this.fields = fields; + } + public PieceColor color; + public List pieces; + public Grid fields; + } + + private void BeginTargetFieldCalculation() + { + if (BGWorker.WorkerSupportsCancellation) + BGWorker.CancelAsync(); + else + BGWorker.RunWorkerAsync(new BGWorkerData(activePlayer, pieces, fields)); + } + private void InitializePieces() { - fields[0, 0].CurrentPiece = new Rook(PieceColor.Black); - fields[7, 0].CurrentPiece = new Rook(PieceColor.Black); - fields[0, 7].CurrentPiece = new Rook(PieceColor.White); - fields[7, 7].CurrentPiece = new Rook(PieceColor.White); + pieces = new List + { + 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), - fields[1, 0].CurrentPiece = new Knight(PieceColor.Black); - fields[6, 0].CurrentPiece = new Knight(PieceColor.Black); - fields[1, 7].CurrentPiece = new Knight(PieceColor.White); - fields[6, 7].CurrentPiece = new Knight(PieceColor.White); + 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), - fields[2, 0].CurrentPiece = new Bishop(PieceColor.Black); - fields[5, 0].CurrentPiece = new Bishop(PieceColor.Black); - fields[2, 7].CurrentPiece = new Bishop(PieceColor.White); - fields[5, 7].CurrentPiece = new Bishop(PieceColor.White); + 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), - fields[4, 0].CurrentPiece = new King(PieceColor.Black); - fields[3, 0].CurrentPiece = new Queen(PieceColor.Black); + new Queen(PieceColor.White, new Vector(3, 7), fields), + new King(PieceColor.White, new Vector(4, 7), fields) + }; - fields[3, 7].CurrentPiece = new Queen(PieceColor.White); - fields[4, 7].CurrentPiece = new King(PieceColor.White); for (int x = 0; x < 8; x++) { - fields[x, 1].CurrentPiece = new Pawn(PieceColor.Black); - fields[x, 6].CurrentPiece = new Pawn(PieceColor.White); + 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 Field[gridSize, gridSize]; - int subPanelEdgeLength = Math.Min(this.Size.Width, this.Size.Height) / gridSize; + 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.gridSize; x++) + for (int x = 0; x < this.GRID_SIZE; x++) { - for (int y = 0; y < this.gridSize; y++) + for (int y = 0; y < this.GRID_SIZE; y++) { - Field field = new Field(x, y); - field.Size = subPanelSize; - field.Location = new System.Drawing.Point(x * subPanelSize.Width, y * subPanelSize.Height); + 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(Vector coordinates) + private void FieldClicked(Field sender) { this.SuspendLayout(); - if (SelectedField.HasValue && validTargetSpots.ContainsKey(coordinates)) // Ein erlaubtes Zielfeld wurde angeklickt + if (FieldIsSelected && SelectedPieceTargetSpots.ContainsKey(sender)) // Ein erlaubtes Zielfeld wurde angeklickt { - DoPieceMove(SelectedField.Value, coordinates); // Bewege Figur + DoPieceMove(SelectedField, sender); // Bewege Figur ResetSelectedField(); // Auswahl zurücksetzen } else { - if (SelectedField == coordinates) // Erneutes Anklicken des Auswahlfeldes + 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 (SelectedField.HasValue) // Wenn ein Feld ausgewählt ist wird die Auswahl gelöscht falls nicht das Auswahlfeld angeklickt wurde + if (FieldIsSelected) // Wenn ein Feld ausgewählt ist wird die Auswahl gelöscht falls nicht das Auswahlfeld angeklickt wurde ResetSelectedField(); // Auswahl zurücksetzen - if (!fields[(int)coordinates.X, (int)coordinates.Y].IsEmpty && fields[(int)coordinates.X, (int)coordinates.Y].CurrentPiece.color == activePlayer) // Feld wird nur ausgewählt, wenn die Farbe der Figur mit der des aktiven Spielers übereinstimmt - SelectedField = coordinates; // Kein Feld ist ausgewählt: Angeklicktes Feld auswählen (!) AKTUALISIERT AUTOMATISCH DIE MARKIERUNGEN + 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); @@ -166,7 +245,7 @@ namespace ChessPanel /// private void ResetSelectedField() { - fields[(int)SelectedField.Value.X, (int)SelectedField.Value.Y].Deselect(); // Auswahl zurücksetzen + SelectedField.Deselect(); // Auswahl zurücksetzen SelectedField = null; // Erlaubte Zielfelder zurücksetzen } #region Helper Can be deleted @@ -186,11 +265,11 @@ namespace ChessPanel private void RefreshSize() { this.SuspendLayout(); - int subPanelEdgeLength = Math.Min(this.Size.Width, this.Size.Height) / gridSize; + 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.gridSize; x++) + for (int x = 0; x < this.GRID_SIZE; x++) { - for (int y = 0; y < this.gridSize; y++) + 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); diff --git a/ChessPanel/ChessGame.cs b/ChessPanel/ChessGame.cs index 95879dd..d29dbf2 100644 --- a/ChessPanel/ChessGame.cs +++ b/ChessPanel/ChessGame.cs @@ -15,24 +15,25 @@ namespace Chess private void InitializeComponent() { - this.board = new ChessBoard(); + this.board = new ChessPanel.ChessBoard(); this.SuspendLayout(); // // board // + this.board.Cursor = System.Windows.Forms.Cursors.Hand; this.board.GridSize = 8; - this.board.Cursor = Cursors.Hand; this.board.Location = new System.Drawing.Point(0, 0); this.board.Name = "board"; - int size = Math.Min(this.Size.Width, this.Size.Height); - board.Size = new System.Drawing.Size(size, size); + this.board.Size = new System.Drawing.Size(100, 100); this.board.TabIndex = 0; + this.board.Paint += new System.Windows.Forms.PaintEventHandler(this.board_Paint); // // ChessGame // this.Controls.Add(this.board); this.Resize += new System.EventHandler(this.ResizeEvent); this.ResumeLayout(false); + } private void ResizeEvent(object sender, EventArgs e) @@ -77,5 +78,10 @@ namespace Chess board.Size = new System.Drawing.Size(size, size); board.Location = this.Size.Width > this.Size.Height ? new System.Drawing.Point((this.Size.Width - size) / 2, 0) : new System.Drawing.Point(0, (this.Size.Height - size) / 2); } + + private void board_Paint(object sender, PaintEventArgs e) + { + + } } } diff --git a/ChessPanel/ChessGame.resx b/ChessPanel/ChessGame.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/ChessPanel/ChessGame.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/ChessPanel/ClassDiagram.cd b/ChessPanel/ClassDiagram.cd deleted file mode 100644 index 2f5e006..0000000 --- a/ChessPanel/ClassDiagram.cd +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - AICAAAAAAAAAAAAQAQAACCAEAIAgJAAACgAAAEoABII= - ChessBoard.cs - - - - - - AAAAAAAAAAAAIAAAAEAAAAACAAAABAAAIAAAAAAAAAA= - ChessGame.cs - - - - - - AABBgAEIEIYEIBAACAAAIAACADAAAEACAAAgQAAAABA= - Field.cs - - - - - - AAAAEAAAACAAAAAAAACAAAACAAAAAAAAAAAAAAAAAAA= - Form1.cs - - - - - - AAABAAAAAAAAAAAAAAAAAAAAEAABAACAAAAAAAgAAAA= - Piece.cs - - - - - - AAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAgAAAA= - Piece.cs - - - - - - AAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAgAAAA= - Piece.cs - - - - - - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAA= - Piece.cs - - - - - - AAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAgAAAA= - Piece.cs - - - - - - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAA= - Piece.cs - - - - - - AAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAgAAAA= - Piece.cs - - - - - - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAA= - Program.cs - - - - - - AAAAAADAgQAQABAAAAIBEAAAIUAAIAAABAACAAAAIIA= - - - - - - AAAAAAAAAAAAAAAAAAAAIAAAAAABAAAAAAAAAAAAAAA= - - - - - - AAAQAQAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAA= - FieldColorSet.cs - - - - \ No newline at end of file diff --git a/ChessPanel/Field.cs b/ChessPanel/Field.cs index 7174998..47240c6 100644 --- a/ChessPanel/Field.cs +++ b/ChessPanel/Field.cs @@ -21,17 +21,35 @@ namespace Chess private FieldColorSet currentEnemyColorSet; private FieldColorSet currentSelectedColorSet; private FieldColorSet currentAllyColorSet; - public delegate void ClickEventHandler(Vector coordinates); + public delegate void ClickEventHandler(Field sender); public event ClickEventHandler FieldClick; public bool IsEmpty { get { return currentPiece == null; } } public Piece currentPiece; public Piece CurrentPiece { - get { return currentPiece; } - set { currentPiece = value; RefreshPiece(); } + get + { + return currentPiece; + } + set + { + currentPiece = value; + RefreshPiece(); + } + } + public override string Text + { + get + { + return ""; + var pos = location.ToString(); + if (IsEmpty) + return pos + Environment.NewLine + "leer"; + return pos + Environment.NewLine + currentPiece.ToString(); + } } - private void RefreshPiece() + public void RefreshPiece() { if (currentPiece == null) this.BackgroundImage = ChessPanel.Properties.Resources.Empty; @@ -40,17 +58,17 @@ namespace Chess } public void Deselect() { - setActiveColorSet(currentNormalColorSet); + SetActiveColorSet(currentNormalColorSet); } public void Highlight(PieceTeam team) // validTargetField { switch (team) { case PieceTeam.Enemy: - setActiveColorSet(currentEnemyColorSet); + SetActiveColorSet(currentEnemyColorSet); break; case PieceTeam.Ally: - setActiveColorSet(currentAllyColorSet); + SetActiveColorSet(currentAllyColorSet); break; default: break; @@ -58,9 +76,9 @@ namespace Chess } public new void Select() // selectedField { - setActiveColorSet(currentSelectedColorSet); + SetActiveColorSet(currentSelectedColorSet); } - private void setActiveColorSet(FieldColorSet set) + private void SetActiveColorSet(FieldColorSet set) { this.BackColor = set.NormalColor; this.FlatAppearance.MouseDownBackColor = set.MouseDownColor; @@ -68,34 +86,36 @@ namespace Chess } public Field(int x, int y) { - this.currentNormalColorSet = (x + y) % 2 == 0 ? primaryNormalColorSet : secondaryNormalColorSet; - this.currentAllyColorSet = (x + y) % 2 == 0 ? primaryValidFriendlyTargetFieldSet : secondaryValidFriendlyTargetFieldSet; - this.currentEnemyColorSet = (x + y) % 2 == 0 ? primaryValidEnemyTargetFieldSet : secondaryValidEnemyTargetFieldSet; - this.currentSelectedColorSet = (x + y) % 2 == 0 ? primarySelectedColorSet : secondarySelectedColorSet; + this.currentNormalColorSet = (x + y) % 2 == 0 ? FieldColorSet.primaryNormalColorSet : FieldColorSet.secondaryNormalColorSet; + this.currentAllyColorSet = (x + y) % 2 == 0 ? FieldColorSet.primaryValidFriendlyTargetFieldSet : FieldColorSet.secondaryValidFriendlyTargetFieldSet; + this.currentEnemyColorSet = (x + y) % 2 == 0 ? FieldColorSet.primaryValidEnemyTargetFieldSet : FieldColorSet.secondaryValidEnemyTargetFieldSet; + this.currentSelectedColorSet = (x + y) % 2 == 0 ? FieldColorSet.primarySelectedColorSet : FieldColorSet.secondarySelectedColorSet; this.FlatStyle = FlatStyle.Flat; this.FlatAppearance.BorderSize = 0; - this.setActiveColorSet(this.currentNormalColorSet); + this.SetActiveColorSet(this.currentNormalColorSet); this.Cursor = Cursors.Arrow; this.location = new Vector(x, y); // NICHT L(!)ocation, der gibt die Position des Buttons in Pixel auf dem Control an! this.Name = string.Format($"field[{x},{y}]"); - this.Text = ""; + this.Text = string.Empty; this.BackgroundImageLayout = ImageLayout.Zoom; this.BackgroundImage = ChessPanel.Properties.Resources.Empty; - this.Click += clicked; + this.Click += Clicked; } - private void clicked(object sender, EventArgs e) + private void Clicked(object sender, EventArgs e) { - FieldClick(this.location); + FieldClick(this); } public override string ToString() { - return this.currentPiece.type.ToString(); + if (IsEmpty) + return "leer"; + return this.currentPiece.ToString(); } } } diff --git a/ChessPanel/FieldColorSet.cs b/ChessPanel/FieldColorSet.cs index 6c4917d..36b7265 100644 --- a/ChessPanel/FieldColorSet.cs +++ b/ChessPanel/FieldColorSet.cs @@ -3,6 +3,14 @@ namespace Chess { struct FieldColorSet { + public static readonly FieldColorSet primaryNormalColorSet = new FieldColorSet(Color.FromArgb(204, 204, 204), Color.FromArgb(153, 153, 153), Color.White); + public static readonly FieldColorSet secondaryNormalColorSet = new FieldColorSet(Color.FromArgb(51, 51, 51), Color.FromArgb(102, 102, 102), Color.Black); + public static readonly FieldColorSet primarySelectedColorSet = new FieldColorSet(Color.FromArgb(204, 204, 102), Color.FromArgb(153, 153, 102), Color.FromArgb(255, 255, 102)); + public static readonly FieldColorSet secondarySelectedColorSet = new FieldColorSet(Color.FromArgb(204, 204, 51), Color.FromArgb(153, 153, 51), Color.FromArgb(255, 255, 51)); + public static readonly FieldColorSet primaryValidFriendlyTargetFieldSet = new FieldColorSet(Color.FromArgb(102, 204, 102), Color.FromArgb(102, 153, 102), Color.FromArgb(102, 255, 102)); + public static readonly FieldColorSet secondaryValidFriendlyTargetFieldSet = new FieldColorSet(Color.FromArgb(51, 204, 51), Color.FromArgb(51, 153, 51), Color.FromArgb(51, 255, 51)); + public static readonly FieldColorSet primaryValidEnemyTargetFieldSet = new FieldColorSet(Color.FromArgb(204, 102, 102), Color.FromArgb(153, 102, 102), Color.FromArgb(255, 102, 102)); + public static readonly FieldColorSet secondaryValidEnemyTargetFieldSet = new FieldColorSet(Color.FromArgb(204, 51, 51), Color.FromArgb(153, 51, 51), Color.FromArgb(255, 51, 51)); public FieldColorSet(Color MOC, Color MDC, Color NC) { MouseOverColor = MOC; diff --git a/ChessPanel/Grid.cs b/ChessPanel/Grid.cs new file mode 100644 index 0000000..f9f3e44 --- /dev/null +++ b/ChessPanel/Grid.cs @@ -0,0 +1,169 @@ +using Chess; +using System; +using System.Windows; +using System.Collections; + +namespace ChessPanel +{ + public class Grid : IEnumerable + { + public Grid(int GridSize) + { + fields = new Field[GridSize, GridSize]; + this.GridSize = GridSize; + } + //public Grid(Field[,] fields) + //{ + // this.GridSize = fields.GetLength(0); + // this.fields = CopyMultiArray(fields); + //} + /// + /// Creates a copy of the given array; + /// + /// + /// + /// + private static T[,] CopyMultiArray(T[,] Array) + { + int[] dim = new int[] { Array.GetLength(0), Array.GetLength(1) }; + T[,] Copy = new T[dim[0], dim[1]]; + for (int x = 0; x < dim[0]; x++) + for (int y = 0; y < dim[1]; y++) + Copy[x, y] = Array[x, y]; + return Copy; + } + //public Grid(Grid fields) : this(fields.fields) { } + public Field[,] fields; + public int GridSize; + public Field this[Vector v] { get { return fields[(int)v.X, (int)v.Y]; } set { fields[(int)v.X, (int)v.Y] = value; } } + + internal Piece GetKing(PieceColor color) + { + foreach (Field item in this) + { + if (item.CurrentPiece?.color == color && item.CurrentPiece?.type == PieceType.King) + return item.CurrentPiece; + } + throw new Exception("No King found"); + } + + public Field this[int x, int y] { get { return fields[x, y]; } set { fields[x, y] = value; } } + public Field this[double x, double y] { get { return fields[(int)x, (int)y]; } set { fields[(int)x, (int)y] = value; } } + /// + /// Adds x and y values to Vector v and gets the field at the position + /// + /// Vector + /// X + /// Y + /// Field + public Field this[Vector v, int x, int y] { get { return fields[x + (int)v.X, y + (int)v.Y]; } set { fields[x + (int)v.X, y + (int)v.Y] = value; } } + public Field this[int x, int y, Vector v] { get { return fields[x + (int)v.X, y + (int)v.Y]; } set { fields[x + (int)v.X, y + (int)v.Y] = value; } } + public Field this[Vector v, double x, double y] + { + get + { + return fields[(int)x + (int)v.X, (int)y + (int)v.Y]; + } + set + { + fields[(int)x + (int)v.X, (int)y + (int)v.Y] = value; + } + } + public Field this[double x, double y, Vector v] { get { return fields[(int)x + (int)v.X, (int)y + (int)v.Y]; } set { fields[(int)x + (int)v.X, (int)y + (int)v.Y] = value; } } + public Field GetFieldWithOffset(Field f, double x, double y) + { + int _x = (int)(f.location.X + x); + int _y = (int)(f.location.Y + y); + return fields[_x, _y]; + } + + + + /// + /// Checks if a field is endagered by a party + /// + /// Reference to the Field that should be checked + /// Color of the attacking party + /// Piece that virtually got moved + /// Field that the movePiece virtually moved to + /// + public bool IsFieldVirtuallyEndagered(Field field, PieceColor color, Piece movePiece, Field targetPos) + { + foreach (Field item in this) + { + if (item.IsEmpty) continue; // Feld ist leer + if (item == movePiece.field) continue; // Quellfeld muss nicht geprüft werden + + Piece p = item.CurrentPiece; + if (p.color != color) continue; // Figur ist kein Gegner + + // Ask every Piece of the other party if it can attack the specified field + if (p.EndageresFieldWithVirtualMove(this, field, movePiece, targetPos)) + //if (item.currentPiece.GetValidTargetFields(movePiece, targetPos).ContainsKey(field)) + return true; + } + return false; + + } + + + + IEnumerator IEnumerable.GetEnumerator() + { + return new FieldEnum(fields); + } + } + + // When you implement IEnumerable, you must also implement IEnumerator. + public class FieldEnum : IEnumerator + { + public Field[,] field; + + // Enumerators are positioned before the first element + // until the first MoveNext() call. + int position = -1; + int width; + int height; + + public FieldEnum(Field[,] list) + { + field = list; + width = list.GetLength(0); + height = list.GetLength(1); + } + + public bool MoveNext() + { + position++; + return (position < field.Length); + } + + public void Reset() + { + position = -1; + } + + object IEnumerator.Current + { + get + { + return Current; + } + } + + public Field Current + { + get + { + try + { + return field[position % 8, position / 8]; + } + catch (IndexOutOfRangeException) + { + throw new InvalidOperationException(); + } + } + } + } +} \ No newline at end of file diff --git a/ChessPanel/MainForm.cs b/ChessPanel/MainForm.cs index b990f16..e3ee155 100644 --- a/ChessPanel/MainForm.cs +++ b/ChessPanel/MainForm.cs @@ -5,11 +5,11 @@ namespace Chess { public partial class MainForm : Form { - bool Fullscreen = false; - bool fullscreen + bool _fullscreen = false; + bool Fullscreen { - get { return Fullscreen; } - set { Fullscreen = value; RefreshFullScreen(); } + get { return _fullscreen; } + set { _fullscreen = value; RefreshFullScreen(); } } public MainForm() { @@ -19,7 +19,7 @@ namespace Chess private void RefreshFullScreen() { this.SuspendLayout(); - if (fullscreen) + if (Fullscreen) { this.WindowState = FormWindowState.Normal; this.FormBorderStyle = FormBorderStyle.None; @@ -36,7 +36,7 @@ namespace Chess private void MainForm_KeyUp(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.F11) - fullscreen = !fullscreen; + Fullscreen = !Fullscreen; } private void MainForm_FormClosing(object sender, FormClosingEventArgs e) @@ -46,7 +46,7 @@ namespace Chess private void MainForm_Load(object sender, EventArgs e) { - fullscreen = true; + Fullscreen = true; } } } diff --git a/ChessPanel/Piece.cs b/ChessPanel/Piece.cs deleted file mode 100644 index 1ddde84..0000000 --- a/ChessPanel/Piece.cs +++ /dev/null @@ -1,461 +0,0 @@ -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 -} \ No newline at end of file diff --git a/ChessPanel/Pieces/AbstractPiece.cs b/ChessPanel/Pieces/AbstractPiece.cs new file mode 100644 index 0000000..f89aa94 --- /dev/null +++ b/ChessPanel/Pieces/AbstractPiece.cs @@ -0,0 +1,232 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using ChessPanel; +using System.Linq; +using System.Windows; + +namespace Chess +{ + public enum PieceColor { White, Black }; + public enum PieceTeam { Enemy, Ally }; + public enum PieceType { King, Queen, Bishop, Rook, Knight, Pawn }; + public enum MoveMode { Normal, Attack, Movement }; + + /// + /// Figur + /// + public abstract class Piece + { + public PieceColor color; + public PieceType type; + public Dictionary validTargetSpots; + public Image image; + public bool HasMoved = false; + public Field field; + public bool EnPassantPossible = false; // Only in Pawn Class. Signs that this Piece has virtually not jumped two pieces, but one, reflective meaning: This.Figure can be attacked using Enpassant if this.type is Pawn + public override string ToString() + { + return type.ToString(); + } + + public Piece(Vector position, Grid fields) + { + this.field = fields[position]; + fields[position].CurrentPiece = this; + } + + public Dictionary RefreshValidTargetSpots(Grid fields, MoveMode mode = MoveMode.Normal) + { + this.validTargetSpots = this.GetValidTargetFields(fields, mode); + return validTargetSpots; + } + + internal void RemoveTargetFieldsWhereKingIsEndangered(Grid fields, Dictionary targetFields) + { + Field ownKingLocation = fields.GetKing(this.color).field; + foreach (var virtualTargetField in targetFields) + { + if (fields.IsFieldVirtuallyEndagered(ownKingLocation, (this.color == PieceColor.Black ? PieceColor.White : PieceColor.Black), this, virtualTargetField.Key)) + targetFields.Remove(virtualTargetField.Key); + } + } + + /// + /// Tests if the Move will leave your King endangered. + /// + /// GameField + /// Location of Piece to move + /// Location to move Piece to + /// Color of Piece to move + /// Bool + /* internal static bool MoveWillEndangerOwnKing(Grid fields, Vector pieceLocation, Vector simulatedLocation, PieceColor color) + { + // fields[simulateLocation].currentPiece = fields[pieceLocation].currentPiece; + // fields[pieceLocation].currentPiece = null; + // Check if own king is endangered + return FieldIsEndangered(fields, simulatedLocation, kingLocation, color, dontTestKingDanger: true); + }*/ + + /// + /// Checks if a specific field can be reached by the figure while a virtual move is simulated + /// + /// Piece that virtually got moved + /// Field that the movePiece virtually moved to + /// Field that should be checked + /// Current Game Grid + /// + internal abstract bool EndageresFieldWithVirtualMove(Grid fields, Field possibleEndageredField, Piece movePiece, Field targetPos); + + internal void Move(Field newPieceField) + { + this.field.CurrentPiece = null; // Remove piece from previous position + this.field = newPieceField; // Set pieces location to new field + newPieceField.CurrentPiece = this; // Set new fields piece to this + } + + /// + /// Tests if the Move will leave your movedPiece endangered. + /// + /// GameField + /// Location of Piece to move + /// Location to move Piece to + /// Color of Piece to move + /// Bool + //internal static bool MoveWillEndangerPiece(Grid fields, Vector pieceLocation, Vector testLocation, PieceColor color) + //{ + // return false; + // //Grid simulatedField = fields; + // //simulatedField[(int)pieceLocation.X, (int)pieceLocation.Y].currentPiece = null; + // //return FieldIsEndangered(fields simulatedField, testLocation, color); + //} + + /// + /// Tests if your King is currently endangered. + /// + /// GameField + /// Kings color + /// + //private static bool KingIsEndangered(Grid fields, PieceColor color) => FieldIsEndangered(fields, GetKingLocation(fields, color), color, dontTestKingDanger: true); + /// + /// Tests if the testLocation is endangered by an enemy. + /// + /// GameField + /// Ally Color + /// Location to test + /// Bool + //private static bool FieldIsEndangered(Grid fields, Vector simulatedLocation, Vector testLocation, PieceColor color, bool dontTestKingDanger = false) + //{ + // foreach (Field field in fields) + // { + // if (field.location != simulatedLocation + // && field.currentPiece != null + // && field.currentPiece.color != color + // && field.currentPiece.GetValidTargetFields(fields, dontTestKingDanger: dontTestKingDanger).ContainsKey(testLocation)) + // return true; + // } + // return false; + //} + /*internal static bool IsEndangeredLocationForPiece(Grid 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(Grid 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(Grid 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, dontTestKingDanger: true).ContainsKey(kingLocation)) + { + return true; + } + } + return false; + }*/ + /// + /// Searches for the King of the given color. + /// + /// GameField + /// Kings color + /// King location as Vector + private static Vector GetKingLocation(Grid fields, PieceColor color) + { + foreach (Field field in fields) + if (!field.IsEmpty && field.currentPiece.type == PieceType.King && field.currentPiece.color == color) + return field.location; + throw new Exception("King not found!"); + } + virtual internal Dictionary GetValidTargetFields(Grid fields, MoveMode mode = MoveMode.Normal, bool dontTestKingDanger = false) + { + var targetFields = GetTargetFields(fields, field, this.color); + if (!dontTestKingDanger) + { + Field kinglocation = fields.GetKing(this.color).field; + List remove = new List(); + + foreach (var item in targetFields.Keys) + { + if (fields.IsFieldVirtuallyEndagered(kinglocation, (this.color == PieceColor.Black ? PieceColor.White : PieceColor.Black), this, item)) + remove.Add(item); + } + foreach (var item in remove) + { + targetFields.Remove(item); + } + } + return targetFields; + } + internal abstract Dictionary GetTargetFields(Grid fields, Field field, PieceColor color); + internal static bool FieldIsVirtuallyEmpty(Field targetPos, Field skipField, Field possibleTargetField) + { + return (possibleTargetField.IsEmpty && possibleTargetField != targetPos) + || possibleTargetField == skipField; + } + internal static bool CheckFieldCanBeReached(Field possibleEndageredField, Field targetPos, Piece movePiece, Field possibleTargetField, PieceColor color, out bool breakIt) + { + breakIt = false; + + var skipField = movePiece.field; + if (FieldIsVirtuallyEmpty(targetPos, skipField, possibleTargetField)) + { + if (possibleTargetField == possibleEndageredField) + return true; + } + else + { + var checkPiece = possibleTargetField == targetPos ? movePiece : possibleTargetField.CurrentPiece; + + if (checkPiece.color != color && possibleTargetField == possibleEndageredField) + return true; + breakIt=true; + } + return false; + } + //internal abstract Dictionary GetValidTargetFields(Grid fields, MoveMode mode = MoveMode.Any, bool dontTestKingDanger = false); + } +} \ No newline at end of file diff --git a/ChessPanel/Pieces/AbstractPiece.txt b/ChessPanel/Pieces/AbstractPiece.txt new file mode 100644 index 0000000..dda78d1 --- /dev/null +++ b/ChessPanel/Pieces/AbstractPiece.txt @@ -0,0 +1,226 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using ChessPanel; +using System.Linq; +using System.Windows; + +namespace Chess +{ + public enum PieceColor { White, Black }; + public enum PieceTeam { Enemy, Ally }; + public enum PieceType { King, Queen, Bishop, Rook, Knight, Pawn }; + public enum MoveMode { Any, Attack, Movement }; + + /// + /// Figur + /// + public abstract class Piece + { + public PieceColor color; + public PieceType type; + public Image image; + public bool HasMoved = false; + public Field field; + private Vector virtualPosition;//? + public bool EnPassantPossible = false; // Only in Pawn Class. Signs that this Piece has virtually not jumped two pieces, but one, reflective meaning: This.Figure can be attacked using Enpassant if this.type is Pawn + public override string ToString() + { + return type.ToString(); + } + + public Piece(Vector position, Grid fields) + { + this.field = fields[position]; + fields[position].CurrentPiece = this; + } + + internal void removeTargetFieldsWhereKingIsEndangered(Grid fields, Dictionary targetFields) + { + Field ownKingLocation = fields.GetKing(this.color).field; + foreach (var virtualTargetField in targetFields) + { + if (fields.IsFieldVirtuallyEndagered(ownKingLocation, (this.color == PieceColor.Black ? PieceColor.White : PieceColor.Black), this, virtualTargetField.Key)) + targetFields.Remove(virtualTargetField.Key); + } + } + + /// + /// Tests if the Move will leave your King endangered. + /// + /// GameField + /// Location of Piece to move + /// Location to move Piece to + /// Color of Piece to move + /// Bool + /* internal static bool MoveWillEndangerOwnKing(Grid fields, Vector pieceLocation, Vector simulatedLocation, PieceColor color) + { + // fields[simulateLocation].currentPiece = fields[pieceLocation].currentPiece; + // fields[pieceLocation].currentPiece = null; + // Check if own king is endangered + return FieldIsEndangered(fields, simulatedLocation, kingLocation, color, dontTestKingDanger: true); + }*/ + + /// + /// Checks if a specific field can be reached by the figure while a virtual move is simulated + /// + /// Piece that virtually got moved + /// Field that the movePiece virtually moved to + /// Field that should be checked + /// Current Game Grid + /// + internal abstract bool EndageresFieldWithVirtualMove(Grid fields, Field possibleEndageredField, Piece movePiece, Field targetPos); + + internal void Move(Field newPieceField) + { + this.field.CurrentPiece = null; // Remove piece from previous position + this.field = newPieceField; // Set pieces location to new field + newPieceField.CurrentPiece = this; // Set new fields piece to this + } + + /// + /// Tests if the Move will leave your movedPiece endangered. + /// + /// GameField + /// Location of Piece to move + /// Location to move Piece to + /// Color of Piece to move + /// Bool + //internal static bool MoveWillEndangerPiece(Grid fields, Vector pieceLocation, Vector testLocation, PieceColor color) + //{ + // return false; + // //Grid simulatedField = fields; + // //simulatedField[(int)pieceLocation.X, (int)pieceLocation.Y].currentPiece = null; + // //return FieldIsEndangered(fields simulatedField, testLocation, color); + //} + + /// + /// Tests if your King is currently endangered. + /// + /// GameField + /// Kings color + /// + //private static bool KingIsEndangered(Grid fields, PieceColor color) => FieldIsEndangered(fields, GetKingLocation(fields, color), color, dontTestKingDanger: true); + /// + /// Tests if the testLocation is endangered by an enemy. + /// + /// GameField + /// Ally Color + /// Location to test + /// Bool + //private static bool FieldIsEndangered(Grid fields, Vector simulatedLocation, Vector testLocation, PieceColor color, bool dontTestKingDanger = false) + //{ + // foreach (Field field in fields) + // { + // if (field.location != simulatedLocation + // && field.currentPiece != null + // && field.currentPiece.color != color + // && field.currentPiece.GetValidTargetFields(fields, dontTestKingDanger: dontTestKingDanger).ContainsKey(testLocation)) + // return true; + // } + // return false; + //} + /*internal static bool IsEndangeredLocationForPiece(Grid 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(Grid 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(Grid 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, dontTestKingDanger: true).ContainsKey(kingLocation)) + { + return true; + } + } + return false; + }*/ + /// + /// Searches for the King of the given color. + /// + /// GameField + /// Kings color + /// King location as Vector + private static Vector GetKingLocation(Grid fields, PieceColor color) + { + foreach (Field field in fields) + if (!field.IsEmpty && field.currentPiece.type == PieceType.King && field.currentPiece.color == color) + return field.location; + throw new Exception("King not found!"); + } + virtual internal Dictionary GetValidTargetFields(Grid fields, MoveMode mode = MoveMode.Any, bool dontTestKingDanger = false) + { + var targetFields = GetTargetFields(fields, field, this.color); + if (!dontTestKingDanger) + { + Field kinglocation = fields.GetKing(this.color).field; + List remove = new List(); + + foreach (var item in targetFields.Keys) + { + if (fields.IsFieldVirtuallyEndagered(kinglocation, (this.color == PieceColor.Black ? PieceColor.White : PieceColor.Black), this, item)) + remove.Add(item); + } + foreach (var item in remove) + { + targetFields.Remove(item); + } + } + return targetFields; + } + internal abstract Dictionary GetTargetFields(Grid fields, Field field, PieceColor color); + internal static bool FieldIsVirtuallyEmpty(Field targetPos, Field skipField, Field possibleTargetField) + { + return (possibleTargetField.IsEmpty && possibleTargetField != targetPos) + || possibleTargetField == skipField; + } + internal static bool checkFieldCanBeReached(Field possibleEndageredField, Field targetPos, Piece movePiece, Field possibleTargetField, PieceColor color, out bool breakIt) + { + breakIt = false; + + var skipField = movePiece.field; + if (FieldIsVirtuallyEmpty(targetPos, skipField, possibleTargetField)) + { + if (possibleTargetField == possibleEndageredField) + return true; + } + else + { + var checkPiece = possibleTargetField == targetPos ? movePiece : possibleTargetField.CurrentPiece; + + if (checkPiece.color != color && possibleTargetField == possibleEndageredField) + return true; + breakIt=true; + } + return false; + } + //internal abstract Dictionary GetValidTargetFields(Grid fields, MoveMode mode = MoveMode.Any, bool dontTestKingDanger = false); + } +} \ No newline at end of file diff --git a/ChessPanel/Pieces/Bishop.cs b/ChessPanel/Pieces/Bishop.cs new file mode 100644 index 0000000..80b2209 --- /dev/null +++ b/ChessPanel/Pieces/Bishop.cs @@ -0,0 +1,143 @@ +using Chess; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows; + +namespace ChessPanel +{ + public class Bishop : Piece + { + public Bishop(PieceColor color, Vector position, Grid fields) : base(position, fields) + { + 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()}"); + } + + private static bool AddFieldToTargetFields(Grid fields, Field field, int x, int y, Dictionary targetFields, PieceColor color) + { + if (fields[field.location, x, y].IsEmpty) + { + targetFields.Add(fields[field.location, x, y], PieceTeam.Ally); + } + else + { + if (fields[field.location, x, y].CurrentPiece?.color != color) + targetFields.Add(fields[field.location, x, y], PieceTeam.Enemy); + return true; + } + return false; + } + internal override Dictionary GetTargetFields(Grid fields, Field field, PieceColor color) + { + return StaticGetTargetFields(fields, field, color); + } + internal static Dictionary StaticGetTargetFields(Grid fields, Field field, PieceColor color) + { + Dictionary targetFields = new Dictionary(); + + #region nach RechtsOben + for (int xy = 1; xy <= 7; xy++) + { + if (CheckOutOfBounds(field, xy, xy) || AddFieldToTargetFields(fields, field, xy, xy, targetFields, color)) + break; + } + #endregion + + // LinksOben + for (int xy = 1; xy <= 7; xy++) + { + if (CheckOutOfBounds(field, -xy, xy) || AddFieldToTargetFields(fields, field, -xy, xy, targetFields, color)) + break; + } + + // RechtsUnten + for (int xy = 1; xy <= 7; xy++) + { + if (CheckOutOfBounds(field, xy, -xy) || AddFieldToTargetFields(fields, field, xy, -xy, targetFields, color)) + break; + } + + // LinksUnten + for (int xy = 1; xy <= 7; xy++) + { + if (CheckOutOfBounds(field, -xy, -xy) || AddFieldToTargetFields(fields, field, -xy, -xy, targetFields, color)) + break; + } + return targetFields; + } + + private static bool CheckOutOfBounds(Field field, int x, int y) + { + return field.location.X + x > 7 || (int)field.location.Y + y > 7 + || field.location.X + x < 0 || (int)field.location.Y + y < 0; + } + + /// + /// + /// + /// Global Field Grid + /// Field that should be checked for endager + /// Piece that should be moved + /// Target of the moved piece + /// + internal override bool EndageresFieldWithVirtualMove(Grid fields, Field possibleEndageredField, Piece movePiece, Field targetPos) + { + return StaticEndageresFieldWithVirtualMove(fields, this.field, possibleEndageredField, movePiece, targetPos, color); + } + + internal static bool StaticEndageresFieldWithVirtualMove(Grid fields, Field thisField, Field possibleEndageredField, Piece movePiece, Field targetPos, PieceColor color) + { + var skipField = movePiece.field; + + for (int xy = 1; xy <= 7; xy++) // nach RechtsOben + { + if (thisField.location.X + xy > 7 || thisField.location.Y + xy > 7) + break; + + var possibleTargetField = fields.GetFieldWithOffset(thisField, xy, xy); + + if (CheckFieldCanBeReached(possibleEndageredField, targetPos, movePiece, possibleTargetField, color, out bool breakIt)) + return true; + if (breakIt) + break; + } + + for (int xy = 1; xy <= 7; xy++) + { + if (thisField.location.X - xy < 0 || thisField.location.Y + xy > 7) // LinksOben + break; + var possibleTargetField = fields.GetFieldWithOffset(thisField, -xy, xy); + + if (CheckFieldCanBeReached(possibleEndageredField, targetPos, movePiece, possibleTargetField, color, out bool breakIt)) + return true; + if (breakIt) + break; + } + for (int xy = 1; xy <= 7; xy++) + { + if (thisField.location.X + xy > 7 || thisField.location.Y - xy < 0) // RechtsUnten + break; + var possibleTargetField = fields.GetFieldWithOffset(thisField, xy, -xy); + + if (CheckFieldCanBeReached(possibleEndageredField, targetPos, movePiece, possibleTargetField, color, out bool breakIt)) + return true; + if (breakIt) + break; + } + for (int xy = 1; xy <= 7; xy++) + { + if (thisField.location.X - xy < 0 || thisField.location.Y - xy < 0) // LinksUnten + break; + var possibleTargetField = fields.GetFieldWithOffset(thisField, -xy, -xy); + + if (CheckFieldCanBeReached(possibleEndageredField, targetPos, movePiece, possibleTargetField, color, out bool breakIt)) + return true; + if (breakIt) + break; + } + return false; + } + } // FINALIZED +} diff --git a/ChessPanel/Pieces/King.cs b/ChessPanel/Pieces/King.cs new file mode 100644 index 0000000..ebdf73f --- /dev/null +++ b/ChessPanel/Pieces/King.cs @@ -0,0 +1,132 @@ +using Chess; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows; + +namespace ChessPanel +{ + public class King : Piece + { + public King(PieceColor color, Vector position, Grid fields) : base(position, fields) + { + 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 bool EndageresFieldWithVirtualMove(Grid fields, Field field, Piece movePiece, Field targetPos) + { + //#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) || field.location.X + x > 7 || field.location.Y + y > 7 || field.location.X + x < 0 || field.location.Y + y < 0) + // continue; + // if (!fields.IsFieldVirtuallyEndagered(fields[field.location, x, y], (this.color == PieceColor.Black ? PieceColor.White : PieceColor.Black), this, fields[field.location, x, y])) + // if ((fields[field.location, x, y].IsEmpty && fields[field.location, x, y] != targetPos) || fields[field.location, x, y] == movePiece.field) + // { + // if (fields[field.location, x, y] == field) + // return true; + // continue; + // } + // else + // { + // if (fields[field.location, x, y].currentPiece.color != color) + // if (fields[field.location, x, y] == field) + // return true; + // break; + // } + // } + //} + //#endregion + return false; + } + + internal override Dictionary GetValidTargetFields(Grid fields, MoveMode mode = MoveMode.Normal, bool dontTestKingDanger = false) + { + var targetFields = GetTargetFields(fields, field, this.color); + if (!dontTestKingDanger) + { + List remove = new List(); + + foreach (var virtualKinglocation in targetFields.Keys) + { + if (fields.IsFieldVirtuallyEndagered(virtualKinglocation, (this.color == PieceColor.Black ? PieceColor.White : PieceColor.Black), this, virtualKinglocation)) + remove.Add(virtualKinglocation); + } + foreach (var item in remove) + { + targetFields.Remove(item); + } + } + return targetFields; + } + + internal override Dictionary GetTargetFields(Grid fields, Field field, PieceColor color) + { + Dictionary targetFields = new Dictionary(); + #region Castling + if (!this.HasMoved && false) // Only Castle if King did not move + foreach (Field 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)field.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 (fields.IsFieldVirtuallyEndagered(fields[x, field.location.Y], (this.color == PieceColor.Black ? PieceColor.White : PieceColor.Black), this, fields[x, field.location.Y])) + { + castling = false; + break; + } + } + if (castling) + { + targetFields.Add(fields[(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) || field.location.X + x > 7 || field.location.Y + y > 7 || field.location.X + x < 0 || field.location.Y + y < 0) + continue; + + if (fields[field.location, x, y].IsEmpty) + { + targetFields.Add(fields[field.location, x, y], PieceTeam.Ally); + } + else + { + if (fields[field.location, x, y].currentPiece.color != color) + targetFields.Add(fields[field.location, x, y], PieceTeam.Enemy); + continue; + } + } + } + #endregion + return targetFields; + } + } // CHECKMATE/CHECK-TEST MISSING +} \ No newline at end of file diff --git a/ChessPanel/Pieces/Knight.cs b/ChessPanel/Pieces/Knight.cs new file mode 100644 index 0000000..cf663db --- /dev/null +++ b/ChessPanel/Pieces/Knight.cs @@ -0,0 +1,98 @@ +using Chess; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows; + +namespace ChessPanel +{ + public class Knight : Piece + { + public Knight(PieceColor color, Vector position, Grid fields) : base(position, fields) + { + 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 bool EndageresFieldWithVirtualMove(Grid fields, Field field, Piece movePiece, Field targetPos) + { + for (int a = -1; a < 2; a += 2) + { + for (int b = -2; b < 3; b += 4) + { + if (!(a + (int)field.location.X > 7 || b + (int)field.location.Y < 0 || a + (int)field.location.X < 0 || b + (int)field.location.Y > 7)) + { + if ((fields[field.location,a,b].IsEmpty && fields[field.location, a, b] != targetPos) || fields[field.location, a, b] == movePiece.field) + { + if (fields[field.location, a, b] == field) + return true; + continue; + } + else + { + if (fields[field.location, a, b].CurrentPiece?.color != color) + if (fields[field.location, a, b] == field) + return true; + break; + } + } + if (!(b + (int)field.location.X > 7 || a + (int)field.location.Y < 0 || b + (int)field.location.X < 0 || a + (int)field.location.Y > 7)) + { + if ((fields[field.location, b, a].IsEmpty && fields[field.location, b, a] != targetPos) || fields[field.location, b, a] == movePiece.field) + { + if (fields[field.location, b, a] == field) + return true; + continue; + } + else + { + if (fields[field.location, b, a].CurrentPiece?.color != color) + if (fields[field.location, b, a] == field) + return true; + break; + } + } + } + } + return false; + } + + internal override Dictionary GetTargetFields(Grid fields, Field field, 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)field.location.X > 7 || b + (int)field.location.Y < 0 || a + (int)field.location.X < 0 || b + (int)field.location.Y > 7)) + { + if (fields[field.location,a,b].IsEmpty) + { + targetFields.Add(fields[field.location, a, b], PieceTeam.Ally); + } + else + { + if (fields[field.location, a, b].CurrentPiece?.color != color) + targetFields.Add(fields[field.location, a, b], PieceTeam.Enemy); + } + } + if (!(b + (int)field.location.X > 7 || a + (int)field.location.Y < 0 || b + (int)field.location.X < 0 || a + (int)field.location.Y > 7)) + { + if (fields[field.location, b, a].IsEmpty) + { + targetFields.Add(fields[field.location, b, a], PieceTeam.Ally); + } + else + { + if (fields[field.location, b, a].CurrentPiece?.color != color) + targetFields.Add(fields[field.location, b, a], PieceTeam.Enemy); + } + } + } + } + return targetFields; + } + } // FINALIZED +} diff --git a/ChessPanel/Pieces/Pawn.cs b/ChessPanel/Pieces/Pawn.cs new file mode 100644 index 0000000..f17b2c1 --- /dev/null +++ b/ChessPanel/Pieces/Pawn.cs @@ -0,0 +1,80 @@ +using Chess; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows; + +namespace ChessPanel +{ + public class Pawn : Piece + { + public Pawn(PieceColor color, Vector position, Grid fields) : base(position, fields) + { + 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 bool EndageresFieldWithVirtualMove(Grid fields, Field field, Piece movePiece, Field targetPos) // Pawn does not care about virtually moved pieces, if field is in range it can attack + { + int direction = this.color == PieceColor.White ? -1 : 1; + #region Attack + for (int x = -1; x < 2; x += 2) + { + if (field.location.Y + (direction) > 7 || field.location.Y + (direction) < 0 || field.location.X + x > 7 || field.location.X + x < 0) + continue; + if (fields[field.location, x, direction] == field) + return true; + } + #endregion + return false; + } + + internal override Dictionary GetTargetFields(Grid fields, Field field, PieceColor color) + { + MoveMode mode = MoveMode.Normal; + + Dictionary targetFields = new Dictionary(); + int direction = this.color == PieceColor.White ? -1 : 1; + #region Movement + if (mode == MoveMode.Normal || mode == MoveMode.Movement) + for (int y = 1; y < 1 + (HasMoved ? 1 : 2); y++) + { + if (field.location.Y + (direction * y) > 7 || field.location.Y + (direction * y) < 0) + break; + if (fields[field.location, 0, (direction * y)].IsEmpty) + targetFields.Add(fields[field.location, 0, (direction * y)], PieceTeam.Ally); + else + break; + } + #endregion + #region Attack + if (mode == MoveMode.Normal || mode == MoveMode.Attack) + { + #region EnPassant + if (field.location.Y == (this.color == PieceColor.White ? 3 : 4)) + for (int x = -1; x < 2; x += 2) + if (field.location.X + x <= 7 && field.location.X + x >= 0) + if (fields[field.location, x, 0].CurrentPiece != null + && fields[field.location, x, 0].CurrentPiece.type == PieceType.Pawn + && fields[field.location, x, 0].CurrentPiece.color != this.color + && fields[field.location, x, 0].CurrentPiece.EnPassantPossible) + targetFields.Add(fields[field.location, x, direction], PieceTeam.Enemy); + #endregion + for (int x = -1; x < 2; x += 2) + { + if (field.location.Y + (direction) > 7 || field.location.Y + (direction) < 0 || field.location.X + x > 7 || field.location.X + x < 0) + continue; + if (fields[field.location, x, direction].CurrentPiece != null && fields[field.location, x, direction].CurrentPiece.color != this.color) + { + targetFields.Add(fields[field.location, x, direction], PieceTeam.Enemy); + } + } + #endregion + } + return targetFields; + } + + } + +} diff --git a/ChessPanel/Pieces/Queen.cs b/ChessPanel/Pieces/Queen.cs new file mode 100644 index 0000000..bb00ee6 --- /dev/null +++ b/ChessPanel/Pieces/Queen.cs @@ -0,0 +1,35 @@ +using Chess; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows; + +namespace ChessPanel +{ + public class Queen : Piece + { + public Queen(PieceColor color, Vector position, Grid fields) : base(position, fields) + { + 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 bool EndageresFieldWithVirtualMove(Grid fields, Field possibleEndageredField, Piece movePiece, Field targetPos) + { + return Rook.StaticEndageresFieldWithVirtualMove(fields, this.field, possibleEndageredField, movePiece, targetPos, color) + || Bishop.StaticEndageresFieldWithVirtualMove(fields, this.field, possibleEndageredField, movePiece, targetPos, color); + } + + internal override Dictionary GetTargetFields(Grid fields, Field field, PieceColor color) + { + Dictionary targetFields = Rook.StaticGetTargetFields(fields, field, this.color); // Take Rook fields + targetFields = targetFields.Concat(Bishop.StaticGetTargetFields(fields, field, this.color) // Add Bishop; Rook + Bishop = Queen + .Where(kvp => !targetFields.ContainsKey(kvp.Key))) + .OrderBy(c => c.Value) + .ToDictionary(c => c.Key, c => c.Value); + return targetFields; + } + } // FINALIZED +} diff --git a/ChessPanel/Pieces/Rook.cs b/ChessPanel/Pieces/Rook.cs new file mode 100644 index 0000000..79e6c5b --- /dev/null +++ b/ChessPanel/Pieces/Rook.cs @@ -0,0 +1,141 @@ +using Chess; +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Windows; + +namespace ChessPanel +{ + public class Rook : Piece + { + public Rook(PieceColor color, Vector position, Grid fields) : base(position, fields) + { + 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(Grid fields, MoveMode mode = MoveMode.Any, bool dontTestKingDanger = false) + //{ + // var targetFields = GetTargetFields(fields, field, this.color); + // if (!dontTestKingDanger) + // { + // Field kinglocation = fields.GetKing(this.color).field; + // foreach (var item in targetFields) + // if (fields.IsFieldVirtuallyEndagered(kinglocation, (this.color == PieceColor.Black ? PieceColor.White : PieceColor.Black), this, item.Key)) + // targetFields.Remove(item.Key); + // } + // return targetFields; + //} + + internal override Dictionary GetTargetFields(Grid fields, Field field, PieceColor color) + { + return StaticGetTargetFields(fields, field, color); + } + internal static Dictionary StaticGetTargetFields(Grid fields, Field field, PieceColor color) + { + Dictionary targetFields = new Dictionary(); + for (int x = (int)field.location.X - 1; x >= 0; x--) // nach Links + { + if (fields[x, field.location.Y].IsEmpty) + { + targetFields.Add(fields[x, field.location.Y], PieceTeam.Ally); + } + else + { + if (fields[x, (int)field.location.Y].currentPiece.color != color) + targetFields.Add(fields[x, field.location.Y], PieceTeam.Enemy); + break; + } + } + for (int x = (int)field.location.X + 1; x <= 7; x++) // nach Rechts + { + if (fields[x, (int)field.location.Y].IsEmpty) + { + targetFields.Add(fields[x, field.location.Y], PieceTeam.Ally); + } + else + { + if (fields[x, (int)field.location.Y].currentPiece.color != color) + targetFields.Add(fields[x, field.location.Y], PieceTeam.Enemy); + break; + } + } + for (int y = (int)field.location.Y - 1; y >= 0; y--) // nach Unten + { + if (fields[(int)field.location.X, y].IsEmpty) + { + targetFields.Add(fields[field.location.X, y], PieceTeam.Ally); + } + else + { + if (fields[(int)field.location.X, y].currentPiece.color != color) + targetFields.Add(fields[field.location.X, y], PieceTeam.Enemy); + break; + } + } + for (int y = (int)field.location.Y + 1; y <= 7; y++) // nach Oben + { + if (fields[(int)field.location.X, y].IsEmpty) + { + targetFields.Add(fields[field.location.X, y], PieceTeam.Ally); + } + else + { + if (fields[(int)field.location.X, y].currentPiece.color != color) + targetFields.Add(fields[field.location.X, y], PieceTeam.Enemy); + break; + } + } + return targetFields; + } + + internal override bool EndageresFieldWithVirtualMove(Grid fields, Field possibleEndageredField, Piece movePiece, Field targetPos) + { + return StaticEndageresFieldWithVirtualMove(fields, this.field, possibleEndageredField, movePiece, targetPos, color); + } + + internal static bool StaticEndageresFieldWithVirtualMove(Grid fields, Field thisField, Field possibleEndageredField, Piece movePiece, Field targetPos, PieceColor color) + { + if (possibleEndageredField.location.X != thisField.location.X && possibleEndageredField.location.Y != thisField.location.Y) // Field can not be reached horizontally nor vertically + return false; + + for (int x = (int)thisField.location.X - 1; x >= 0; x--) // nach Links + { + var possibleTargetField = fields[x, thisField.location.Y]; + + if (CheckFieldCanBeReached(possibleEndageredField, targetPos, movePiece, possibleTargetField, color, out bool breakIt)) + return true; + if (breakIt) + break; + } + for (int x = (int)thisField.location.X + 1; x <= 7; x++) // nach Rechts + { + var possibleTargetField = fields[x, thisField.location.Y]; + + if (CheckFieldCanBeReached(possibleEndageredField, targetPos, movePiece, possibleTargetField, color, out bool breakIt)) + return true; + if (breakIt) + break; + } + for (int y = (int)thisField.location.Y - 1; y >= 0; y--) // nach Oben + { + var possibleTargetField = fields[thisField.location.X, y]; + + if (CheckFieldCanBeReached(possibleEndageredField, targetPos, movePiece, possibleTargetField, color, out bool breakIt)) + return true; + if (breakIt) + break; + } + for (int y = (int)thisField.location.Y + 1; y <= 7; y++) // nach Unten + { + var possibleTargetField = fields[thisField.location.X, y]; + + if (CheckFieldCanBeReached(possibleEndageredField, targetPos, movePiece, possibleTargetField, color, out bool breakIt)) + return true; + if (breakIt) + break; + } + return false; + } + } // FINALIZED +}