From de2858f7f93d3652e5cbdddc169b84054ce4b4f1 Mon Sep 17 00:00:00 2001 From: Christian Nagel Date: Sat, 7 Sep 2024 11:30:34 +0200 Subject: [PATCH 1/3] unit tests for #235 --- .../Analyzers/ShapeGame5x5x4AnalyzerTests.cs | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/services/common/Codebreaker.GameAPIs.Analyzers.Tests/Analyzers/ShapeGame5x5x4AnalyzerTests.cs b/src/services/common/Codebreaker.GameAPIs.Analyzers.Tests/Analyzers/ShapeGame5x5x4AnalyzerTests.cs index 54e0bf74..8e8c4e0a 100644 --- a/src/services/common/Codebreaker.GameAPIs.Analyzers.Tests/Analyzers/ShapeGame5x5x4AnalyzerTests.cs +++ b/src/services/common/Codebreaker.GameAPIs.Analyzers.Tests/Analyzers/ShapeGame5x5x4AnalyzerTests.cs @@ -7,6 +7,34 @@ namespace Codebreaker.GameAPIs.Analyzer.Tests; public class ShapeGame5x5x4AnalyzerTests { + [Fact] + public void SetMove_ShouldNotReturnBlueWithOneWhite() + { + ShapeAndColorResult expectedKeyPegs = new(0, 1, 0); + ShapeAndColorResult? resultKeyPegs = AnalyzeGame( + ["Rectangle;Green", "Triangle;Blue", "Square;Blue", "Triangle;Green"], + ["Circle;Red", "Square;Green", "Triangle;Blue", "Star;Yellow"] + ); + // Position 3: Triangle.Blue is correct, but should be in the 2nd position + // all the other pegs are incorrect + + Assert.Equal(expectedKeyPegs, resultKeyPegs); + } + + [Fact] + public void SetMove_ShouldReturnOneWhiteAndOneBlue() + { + ShapeAndColorResult expectedKeyPegs = new(0, 1, 1); + ShapeAndColorResult? resultKeyPegs = AnalyzeGame( + ["Rectangle;Purple", "Square;Purple", "Star;Red", "Circle;Yellow"], + ["Triangle;Purple", "Star;Green", "Circle;Blue", "Square;Purple"] + ); + // position 4: Square;Purple is correct but in an incorrect position (should be 2) - white + // position 1: Purple correct - blue + + Assert.Equal(expectedKeyPegs, resultKeyPegs); + } + [Fact] public void SetMove_ShouldReturnTwoBlack() { @@ -111,7 +139,7 @@ public void SetMove_ShouldReturnTwoBlueForMatchingShapes() [Fact] public void SetMove_ShouldReturnOneBlackAndOneWhite() { - // the first and second guess have a correct shape, but both in the wrong positon + // the first and second guess have a correct shape, but both in the wrong position // all the colors are incorrect ShapeAndColorResult expectedKeyPegs = new(1, 1, 0); ShapeAndColorResult? resultKeyPegs = AnalyzeGame( From 54798ee27529a243fdc21753f211a481f9c5b085 Mon Sep 17 00:00:00 2001 From: Christian Nagel Date: Sat, 7 Sep 2024 13:20:44 +0200 Subject: [PATCH 2/3] fix 5x5x4 algorithm #235 --- .../Analyzers/ShapeGameGuessAnalyzer.cs | 34 +++++++++++-------- .../Fields/ShapeAndColorField.cs | 2 ++ 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/services/common/Codebreaker.GameAPIs.Analyzers/Analyzers/ShapeGameGuessAnalyzer.cs b/src/services/common/Codebreaker.GameAPIs.Analyzers/Analyzers/ShapeGameGuessAnalyzer.cs index 79fab25d..9248f2e5 100644 --- a/src/services/common/Codebreaker.GameAPIs.Analyzers/Analyzers/ShapeGameGuessAnalyzer.cs +++ b/src/services/common/Codebreaker.GameAPIs.Analyzers/Analyzers/ShapeGameGuessAnalyzer.cs @@ -20,16 +20,16 @@ protected override void ValidateGuessValues() protected override ShapeAndColorResult GetCoreResult() { // Check black, white and blue keyPegs - List codesToCheck = [.._game.Codes.ToPegs() ]; - List guessPegsToCheck = [.. Guesses ]; - List remainingCodesToCheck = []; - List remainingGuessPegsToCheck = []; + List codesToCheck = [.._game.Codes.ToPegs() ]; // all the codes that need to be verified with the actual check + List guessPegsToCheck = [.. Guesses ]; // all the guesses that need to be verified with the actual check + List remainingCodesToCheck = []; // the codes that need to be checked with the check following - filled by the actual check + List remainingGuessPegsToCheck = []; // the guesses that need to be checked with the check following - filled by the actual check byte black = 0; byte white = 0; byte blue = 0; - // check for black (correct color and shape at the correct position) + // first check for black (correct color and shape at the correct position) // add the remaining codes and guess pegs to the remaining lists to check for white and blue keyPegs for (int i = 0; i < guessPegsToCheck.Count; i++) { @@ -44,36 +44,40 @@ protected override ShapeAndColorResult GetCoreResult() } } + // next check for white (correct pair at a wrong position) + // add the remaining codes and guess pegs to the remaining lists to check for blue keyPegs codesToCheck = remainingCodesToCheck; - remainingCodesToCheck = new(codesToCheck); guessPegsToCheck = remainingGuessPegsToCheck; - remainingGuessPegsToCheck = []; + remainingCodesToCheck = new(codesToCheck); + remainingGuessPegsToCheck = Enumerable.Repeat(ShapeAndColorField.Empty, guessPegsToCheck.Count).ToList(); - // check for white (correct pair at a wrong position) - // and add the remaining codes and guess pegs to the remaining lists to check for blue keyPegs for (int i = 0; i < guessPegsToCheck.Count; i++) { ShapeAndColorField? codeField = codesToCheck.FirstOrDefault(c => c == guessPegsToCheck[i]); if (codeField is not null) { white++; - codesToCheck.Remove(codeField); // remove for the white check - remainingCodesToCheck.Remove(codeField); // remove for the blue check + + var ix = codesToCheck.IndexOf(codeField); + codesToCheck[ix] = ShapeAndColorField.Empty; // this code is a match and thus no longer is used when checking for white + remainingCodesToCheck[ix] = ShapeAndColorField.Empty; // this code is also not used with the next blue check } else { - remainingGuessPegsToCheck.Add(guessPegsToCheck[i]); // add for the blue check + remainingGuessPegsToCheck[i] = guessPegsToCheck[i]; // not a match for the guess, thus it needs to be added for the blue check } } + // check blue (either the shape or the color is in the correct position but with a wrong paired element) codesToCheck = remainingCodesToCheck; guessPegsToCheck = remainingGuessPegsToCheck; - // check blue (either the shape or the color is in the correct position but with a wrong paired element) for (int i = 0; i < guessPegsToCheck.Count; i++) { - if (guessPegsToCheck[i].Shape == codesToCheck[i].Shape || - guessPegsToCheck[i].Color == codesToCheck[i].Color) + if ((guessPegsToCheck[i] != ShapeAndColorField.Empty || + codesToCheck[i] != ShapeAndColorField.Empty) && + (guessPegsToCheck[i].Shape == codesToCheck[i].Shape || + guessPegsToCheck[i].Color == codesToCheck[i].Color)) { blue++; } diff --git a/src/services/common/Codebreaker.GameAPIs.Analyzers/Fields/ShapeAndColorField.cs b/src/services/common/Codebreaker.GameAPIs.Analyzers/Fields/ShapeAndColorField.cs index ab5f6dd7..d1901c51 100644 --- a/src/services/common/Codebreaker.GameAPIs.Analyzers/Fields/ShapeAndColorField.cs +++ b/src/services/common/Codebreaker.GameAPIs.Analyzers/Fields/ShapeAndColorField.cs @@ -2,6 +2,8 @@ public partial record class ShapeAndColorField(string Shape, string Color) { + internal static ShapeAndColorField Empty => new ShapeAndColorField(string.Empty, string.Empty); + private const char Separator = ';'; public override string ToString() => $"{Shape}{Separator}{Color}"; From a4f8715b10a8deabe2137f3e3eeef4b0e6614237 Mon Sep 17 00:00:00 2001 From: Christian Nagel Date: Sat, 7 Sep 2024 13:29:57 +0200 Subject: [PATCH 3/3] add a VersionPrefix to publish it independent of the other packages that are already preview version 3.8.x --- .../Codebreaker.GameAPIs.Analyzers/Codebreaker.Analyzers.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/common/Codebreaker.GameAPIs.Analyzers/Codebreaker.Analyzers.csproj b/src/services/common/Codebreaker.GameAPIs.Analyzers/Codebreaker.Analyzers.csproj index 0a4806ab..6e499748 100644 --- a/src/services/common/Codebreaker.GameAPIs.Analyzers/Codebreaker.Analyzers.csproj +++ b/src/services/common/Codebreaker.GameAPIs.Analyzers/Codebreaker.Analyzers.csproj @@ -6,6 +6,7 @@ enable enable latest + 3.7.1 Codebreaker;CNinnovation;GameAnalyzers