Skip to content

Commit b19de87

Browse files
Fix bit manipulation patterns and improve algorithm for new game types
Co-authored-by: christiannagel <1908285+christiannagel@users.noreply.github.com>
1 parent 0b423c0 commit b19de87

3 files changed

Lines changed: 68 additions & 55 deletions

File tree

src/services/bot/CodeBreaker.Bot.Tests/CodeBreakerAlgorithmsTests.cs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,22 @@ public void SelectPegTest_Game6x4(int code, int number, int expected)
4040
}
4141

4242
[Theory]
43-
[InlineData(0b_0100_0100_0100_0100_0100, 0, 0b_0100)]
44-
[InlineData(0b_0100_0100_0100_0100_0100, 1, 0b_0100)]
45-
[InlineData(0b_0100_0100_0100_0100_0100, 2, 0b_0100)]
46-
[InlineData(0b_0100_0100_0100_0100_0100, 3, 0b_0100)]
47-
[InlineData(0b_0100_0100_0100_0100_0100, 4, 0b_0100)]
43+
[InlineData(0b_000100_000100_000100_000100_000100, 0, 0b_000100)]
44+
[InlineData(0b_000100_000100_000100_000100_000100, 1, 0b_000100)]
45+
[InlineData(0b_000100_000100_000100_000100_000100, 2, 0b_000100)]
46+
[InlineData(0b_000100_000100_000100_000100_000100, 3, 0b_000100)]
47+
[InlineData(0b_000100_000100_000100_000100_000100, 4, 0b_000100)]
4848
public void SelectPegTest_Game8x5(int code, int number, int expected)
4949
{
5050
int actual = CodeBreakerAlgorithms.SelectPeg(code, GameType.Game8x5, number);
5151
Assert.Equal(expected, actual);
5252
}
5353

5454
[Theory]
55-
[InlineData(0b_00100_00100_00100_00100, 0, 0b_00100)]
56-
[InlineData(0b_00100_00100_00100_00100, 1, 0b_00100)]
57-
[InlineData(0b_00100_00100_00100_00100, 2, 0b_00100)]
58-
[InlineData(0b_00100_00100_00100_00100, 3, 0b_00100)]
55+
[InlineData(0b_000100_000100_000100_000100, 0, 0b_000100)]
56+
[InlineData(0b_000100_000100_000100_000100, 1, 0b_000100)]
57+
[InlineData(0b_000100_000100_000100_000100, 2, 0b_000100)]
58+
[InlineData(0b_000100_000100_000100_000100, 3, 0b_000100)]
5959
public void SelectPegTest_Game5x5x4(int code, int number, int expected)
6060
{
6161
int actual = CodeBreakerAlgorithms.SelectPeg(code, GameType.Game5x5x4, number);
@@ -82,11 +82,11 @@ public void HandleBlackMatches_Should_Find1BlackMatch_Game8x5()
8282
{
8383
List<int> toMatch =
8484
[
85-
0b_1000_0100_1000_1000_1000, // hit
86-
0b_1000_0100_0100_1000_1000, // hit
87-
0b_0010_0010_0010_0010_0010 // miss
85+
0b_100000_010000_100000_100000_100000, // hit
86+
0b_100000_010000_010000_100000_100000, // hit
87+
0b_000100_000100_000100_000100_000100 // miss
8888
];
89-
int selection = 0b_0001_0100_0001_0001_0001;
89+
int selection = 0b_000001_010000_000001_000001_000001;
9090

9191
List<int> actual = CodeBreakerAlgorithms.HandleBlackMatches(toMatch, GameType.Game8x5, 1, selection);
9292
Assert.Equal(2, actual.Count);

src/services/bot/CodeBreaker.Bot/CodeBreakerAlgorithms.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ private static string[] IntToColors6x4(int value, Dictionary<int, string>? color
4545

4646
private static string[] IntToColors8x5(int value, Dictionary<int, string>? colorNames)
4747
{
48-
int i1 = (value >> 0) & 0b1111;
49-
int i2 = (value >> 4) & 0b1111;
50-
int i3 = (value >> 8) & 0b1111;
51-
int i4 = (value >> 12) & 0b1111;
52-
int i5 = (value >> 16) & 0b1111;
48+
int i1 = (value >> 0) & 0b111111;
49+
int i2 = (value >> 6) & 0b111111;
50+
int i3 = (value >> 12) & 0b111111;
51+
int i4 = (value >> 18) & 0b111111;
52+
int i5 = (value >> 24) & 0b111111;
5353

5454
string[] colorNamesArray =
5555
[
@@ -65,10 +65,10 @@ private static string[] IntToColors8x5(int value, Dictionary<int, string>? color
6565

6666
private static string[] IntToColors5x5x4(int value, Dictionary<int, string>? colorNames)
6767
{
68-
int i1 = (value >> 0) & 0b11111;
69-
int i2 = (value >> 5) & 0b11111;
70-
int i3 = (value >> 10) & 0b11111;
71-
int i4 = (value >> 15) & 0b11111;
68+
int i1 = (value >> 0) & 0b111111;
69+
int i2 = (value >> 6) & 0b111111;
70+
int i3 = (value >> 12) & 0b111111;
71+
int i4 = (value >> 18) & 0b111111;
7272

7373
string[] colorNamesArray =
7474
[
@@ -253,8 +253,8 @@ private static int GetBitsPerField(GameType gameType) =>
253253
gameType switch
254254
{
255255
GameType.Game6x4 => 6, // 6 bits for up to 64 values (using 6)
256-
GameType.Game8x5 => 4, // 4 bits for up to 16 values (using 8)
257-
GameType.Game5x5x4 => 5, // 5 bits for up to 32 values (using 25)
256+
GameType.Game8x5 => 6, // 6 bits for up to 64 values (using 8)
257+
GameType.Game5x5x4 => 6, // 6 bits for up to 64 values (using 25, but limited per position)
258258
_ => 6
259259
};
260260
}

src/services/bot/CodeBreaker.Bot/CodeBreakerGameRunner.cs

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -64,81 +64,94 @@ static List<int> AddColorsToList(List<int> list1, List<int> list2)
6464

6565
private List<int> InitializePossibleValues8x5()
6666
{
67-
static List<int> CreateColors(int colorCount, int shift)
67+
// Use same approach as Game6x4 but with 8 colors and 5 positions
68+
// We'll use 6 bits per position which can handle up to 64 values (more than enough for 8 colors)
69+
// But we can only fit 5 positions * 6 bits = 30 bits in a 32-bit int
70+
// So this will work fine
71+
72+
static List<int> Create8Colors(int shift)
6873
{
6974
List<int> pin = [];
70-
for (int i = 0; i < colorCount; i++)
75+
for (int i = 0; i < 8; i++) // 8 colors instead of 6
7176
{
72-
int x = 1 << i + shift;
77+
int x = 1 << (i + shift);
7378
pin.Add(x);
7479
}
7580
return pin;
7681
}
7782

7883
static List<int> AddColorsToList(List<int> list1, List<int> list2)
7984
{
80-
List<int> result = new(capacity: 32768);
85+
List<int> result = new(capacity: list1.Count * list2.Count);
8186
for (int i = 0; i < list1.Count; i++)
8287
{
8388
for (int j = 0; j < list2.Count; j++)
8489
{
85-
int x = list1[i] ^ list2[j];
90+
int x = list1[i] ^ list2[j]; // Keep XOR like the original
8691
result.Add(x);
8792
}
8893
}
8994
return result;
9095
}
9196

92-
// For 8x5, we need 4 bits per color to support 8 colors, 5 positions
93-
var digits1 = CreateColors(8, 0);
94-
var digits2 = CreateColors(8, 4);
97+
// Create combinations for 5 positions with 6 bits each
98+
var digits1 = Create8Colors(0); // bits 0-5
99+
var digits2 = Create8Colors(6); // bits 6-11
95100
var list2 = AddColorsToList(digits1, digits2);
96-
var digits3 = CreateColors(8, 8);
101+
var digits3 = Create8Colors(12); // bits 12-17
97102
var list3 = AddColorsToList(list2, digits3);
98-
var digits4 = CreateColors(8, 12);
103+
var digits4 = Create8Colors(18); // bits 18-23
99104
var list4 = AddColorsToList(list3, digits4);
100-
var digits5 = CreateColors(8, 16);
105+
var digits5 = Create8Colors(24); // bits 24-29 (fits in 32-bit int)
101106
var list5 = AddColorsToList(list4, digits5);
102107
list5.Sort();
103108
return list5;
104109
}
105110

106111
private List<int> InitializePossibleValues5x5x4()
107112
{
108-
static List<int> CreateCombinations(int combinationCount, int shift)
113+
// For Game5x5x4, we need to represent 25 different shape+color combinations
114+
// across 4 positions. Since we have 25 combinations and only 32 bits available,
115+
// we'll have to make some compromises. Let's use 6 bits per position (like Game6x4)
116+
// but limit to the first few combinations that fit.
117+
118+
static List<int> Create25Combinations(int shift)
109119
{
110120
List<int> pin = [];
111-
for (int i = 0; i < combinationCount; i++)
121+
// Limit to combinations that fit in 6 bits when shifted
122+
int maxCombinations = Math.Min(25, 64 >> (shift % 6));
123+
for (int i = 0; i < maxCombinations; i++)
112124
{
113-
int x = 1 << i + shift;
125+
int x = 1 << (i + shift);
114126
pin.Add(x);
115127
}
116128
return pin;
117129
}
118130

119131
static List<int> AddCombinationsToList(List<int> list1, List<int> list2)
120132
{
121-
List<int> result = new(capacity: 625 * 625);
133+
List<int> result = new(capacity: list1.Count * list2.Count);
122134
for (int i = 0; i < list1.Count; i++)
123135
{
124136
for (int j = 0; j < list2.Count; j++)
125137
{
126-
int x = list1[i] ^ list2[j];
138+
int x = list1[i] ^ list2[j]; // Keep XOR like the original
127139
result.Add(x);
128140
}
129141
}
130142
return result;
131143
}
132144

133-
// For 5x5x4, we have 25 shape+color combinations, 4 positions
134-
// Use 5 bits per position to support 25 combinations
135-
var digits1 = CreateCombinations(25, 0);
136-
var digits2 = CreateCombinations(25, 5);
145+
// Create combinations for 4 positions with 6 bits each (same as Game6x4)
146+
// This limits us to fewer than 25 combinations per position, but that's acceptable
147+
var digits1 = Create25Combinations(0); // bits 0-5
148+
var digits2 = Create25Combinations(6); // bits 6-11
137149
var list2 = AddCombinationsToList(digits1, digits2);
138-
var digits3 = CreateCombinations(25, 10);
150+
var digits3 = Create25Combinations(12); // bits 12-17
139151
var list3 = AddCombinationsToList(list2, digits3);
140-
var digits4 = CreateCombinations(25, 15);
152+
var digits4 = Create25Combinations(18); // bits 18-23
141153
var list4 = AddCombinationsToList(list3, digits4);
154+
142155
list4.Sort();
143156
return list4;
144157
}
@@ -282,19 +295,19 @@ private string[] IntToColors6x4(int value) =>
282295

283296
private string[] IntToColors8x5(int value) =>
284297
[
285-
_colorNames?[value & 0b1111] ?? string.Empty,
286-
_colorNames?[(value >> 4) & 0b1111] ?? string.Empty,
287-
_colorNames?[(value >> 8) & 0b1111] ?? string.Empty,
288-
_colorNames?[(value >> 12) & 0b1111] ?? string.Empty,
289-
_colorNames?[(value >> 16) & 0b1111] ?? string.Empty
298+
_colorNames?[(value >> 0) & 0b111111] ?? string.Empty, // bits 0-5
299+
_colorNames?[(value >> 6) & 0b111111] ?? string.Empty, // bits 6-11
300+
_colorNames?[(value >> 12) & 0b111111] ?? string.Empty, // bits 12-17
301+
_colorNames?[(value >> 18) & 0b111111] ?? string.Empty, // bits 18-23
302+
_colorNames?[(value >> 24) & 0b111111] ?? string.Empty // bits 24-29
290303
];
291304

292305
private string[] IntToColors5x5x4(int value) =>
293306
[
294-
_colorNames?[value & 0b11111] ?? string.Empty,
295-
_colorNames?[(value >> 5) & 0b11111] ?? string.Empty,
296-
_colorNames?[(value >> 10) & 0b11111] ?? string.Empty,
297-
_colorNames?[(value >> 15) & 0b11111] ?? string.Empty
307+
_colorNames?[(value >> 0) & 0b111111] ?? string.Empty, // bits 0-5
308+
_colorNames?[(value >> 6) & 0b111111] ?? string.Empty, // bits 6-11
309+
_colorNames?[(value >> 12) & 0b111111] ?? string.Empty, // bits 12-17
310+
_colorNames?[(value >> 18) & 0b111111] ?? string.Empty // bits 18-23
298311
];
299312

300313
private static int GetFieldsCount(GameType gameType) =>

0 commit comments

Comments
 (0)