diff --git a/lib/utils/checkout_helper.dart b/lib/utils/checkout_helper.dart index 6699dd8..3bece73 100644 --- a/lib/utils/checkout_helper.dart +++ b/lib/utils/checkout_helper.dart @@ -28,40 +28,40 @@ abstract final class CheckoutHelper { 16: ['D8'], 17: ['S1', 'D8'], 18: ['D9'], - 19: ['S3', 'D8'], + 19: ['S1', 'D9'], 20: ['D10'], 21: ['S1', 'D10'], 22: ['D11'], - 23: ['S7', 'D8'], + 23: ['S1', 'D11'], 24: ['D12'], - 25: ['S9', 'D8'], + 25: ['S1', 'D12'], 26: ['D13'], - 27: ['S3', 'D12'], + 27: ['S1', 'D13'], 28: ['D14'], 29: ['S1', 'D14'], 30: ['D15'], - 31: ['S7', 'D12'], + 31: ['S1', 'D15'], 32: ['D16'], 33: ['S1', 'D16'], 34: ['D17'], - 35: ['S3', 'D16'], + 35: ['S1', 'D17'], 36: ['D18'], 37: ['S1', 'D18'], 38: ['D19'], - 39: ['S7', 'D16'], + 39: ['S1', 'D19'], 40: ['D20'], - 41: ['S1', 'D20'], - 42: ['D21'], // outer bull D21 doesn't exist — S10, D16 - 43: ['S3', 'D20'], - 44: ['D22'], // S4, D20 - 45: ['S5', 'D20'], + 41: ['S9', 'D16'], + 42: ['S10', 'D16'], + 43: ['S11', 'D16'], + 44: ['S12', 'D16'], + 45: ['S13', 'D16'], 46: ['S6', 'D20'], - 47: ['S7', 'D20'], - 48: ['D24'], + 47: ['S15', 'D16'], + 48: ['S8', 'D20'], 49: ['S9', 'D20'], - 50: ['Bull'], + 50: ['S10', 'D20'], 51: ['S11', 'D20'], - 52: ['D16', 'D10'], // S12, D20 + 52: ['S12', 'D20'], 53: ['S13', 'D20'], 54: ['S14', 'D20'], 55: ['S15', 'D20'], @@ -70,27 +70,27 @@ abstract final class CheckoutHelper { 58: ['S18', 'D20'], 59: ['S19', 'D20'], 60: ['S20', 'D20'], - 61: ['S1', 'Bull'], // or T15, D8 - 62: ['S2', 'Bull'], - 63: ['S3', 'Bull'], // or T13, D12 + 61: ['T15', 'D8'], + 62: ['T10', 'D16'], + 63: ['T17', 'D6'], 64: ['T16', 'D8'], - 65: ['T15', 'D10'], + 65: ['T11', 'D16'], 66: ['T10', 'D18'], - 67: ['T17', 'D8'], - 68: ['T12', 'D16'], // or T20, D4 - 69: ['T19', 'D6'], // or T15, D12 - 70: ['T18', 'D8'], // or T10, D20 + 67: ['T9', 'D20'], + 68: ['T16', 'D10'], + 69: ['T19', 'D6'], + 70: ['T18', 'D8'], 71: ['T13', 'D16'], - 72: ['T12', 'D18'], // or T16, D12 + 72: ['T16', 'D12'], 73: ['T19', 'D8'], 74: ['T14', 'D16'], - 75: ['T17', 'D12'], // or T15, D15 - 76: ['T20', 'D8'], - 77: ['T19', 'D10'], // or T7, D28 (not valid) — T15, D16 + 75: ['T17', 'D12'], + 76: ['T16', 'D14'], + 77: ['T19', 'D10'], 78: ['T18', 'D12'], - 79: ['T13', 'D20'], + 79: ['T19', 'D11'], 80: ['T20', 'D10'], - 81: ['T19', 'D12'], // or T15, D18 + 81: ['T19', 'D12'], 82: ['T14', 'D20'], 83: ['T17', 'D16'], 84: ['T20', 'D12'], @@ -108,50 +108,50 @@ abstract final class CheckoutHelper { 96: ['T20', 'D18'], 97: ['T19', 'D20'], 98: ['T20', 'D19'], - 99: ['T19', 'D21'], // T19, S10, D16 — use T19, Bull + 99: ['T19', 'S10', 'D16'], 100: ['T20', 'D20'], - 101: ['T17', 'D25'], // T17, Bull - 102: ['T20', 'D21'], // T20, S2, D20 - 103: ['T19', 'D23'], // T19, S6, D20 - 104: ['T18', 'D25'], // T18, Bull - 105: ['T20', 'D22'], // T20, S5, D20 - 106: ['T20', 'D23'], // T20, S6, D20 - 107: ['T19', 'D25'], // T19, Bull - 108: ['T20', 'D24'], // T20, S8, D20 - 109: ['T20', 'D24'], // T19, S12, D20 - 110: ['T20', 'D25'], // T20, Bull - 111: ['T20', 'S11', 'D20'], - 112: ['T20', 'S12', 'D20'], - 113: ['T20', 'S13', 'D20'], + 101: ['T20', 'S9', 'D16'], + 102: ['T20', 'S10', 'D16'], + 103: ['T19', 'S6', 'D20'], + 104: ['T16', 'S16', 'D20'], + 105: ['T19', 'S16', 'D16'], + 106: ['T20', 'S6', 'D20'], + 107: ['T20', 'S15', 'D16'], + 108: ['T20', 'S16', 'D16'], + 109: ['T20', 'S9', 'D20'], + 110: ['T20', 'S10', 'D20'], + 111: ['T19', 'S14', 'D20'], + 112: ['T20', 'S20', 'D16'], + 113: ['T19', 'S16', 'D20'], 114: ['T20', 'S14', 'D20'], - 115: ['T20', 'S15', 'D20'], - 116: ['T20', 'S16', 'D20'], + 115: ['T19', 'S18', 'D20'], + 116: ['T19', 'S19', 'D20'], 117: ['T20', 'S17', 'D20'], 118: ['T20', 'S18', 'D20'], - 119: ['T20', 'S19', 'D20'], + 119: ['T19', 'T12', 'D13'], 120: ['T20', 'S20', 'D20'], - 121: ['T20', 'S11', 'Bull'], - 122: ['T18', 'T16', 'D14'], // T18, S14, D20 — simplified - 123: ['T19', 'S6', 'Bull'], - 124: ['T20', 'T4', 'D20'], // T20, S4 = not quite right - 125: ['T20', 'S5', 'Bull'], // T25 doesn't exist - 126: ['T19', 'S9', 'Bull'], - 127: ['T20', 'S7', 'Bull'], + 121: ['T20', 'T11', 'D14'], + 122: ['T18', 'T20', 'D4'], + 123: ['T19', 'T16', 'D9'], + 124: ['T20', 'T16', 'D8'], + 125: ['T18', 'T13', 'D16'], + 126: ['T19', 'T19', 'D6'], + 127: ['T20', 'T17', 'D8'], 128: ['T18', 'T14', 'D16'], - 129: ['T19', 'T12', 'D12'], - 130: ['T20', 'T10', 'D20'], - 131: ['T20', 'S11', 'Bull'], // duplicate of 121 — T19, T14, D12 - 132: ['T20', 'T16', 'D12'], - 133: ['T20', 'T7', 'D24'], // T20, T19, D8 + 129: ['T19', 'T12', 'D18'], + 130: ['T20', 'T20', 'D5'], + 131: ['T20', 'T13', 'D16'], + 132: ['Outer', 'T19', 'Bull'], + 133: ['T20', 'T19', 'D8'], 134: ['T20', 'T14', 'D16'], - 135: ['T20', 'T15', 'D15'], - 136: ['T20', 'T16', 'D14'], - 137: ['T20', 'T19', 'D10'], // T20, T15, D16 + 135: ['Outer', 'T20', 'Bull'], + 136: ['T20', 'T20', 'D8'], + 137: ['T20', 'T15', 'D16'], 138: ['T20', 'T18', 'D12'], - 139: ['T19', 'T14', 'D20'], - 140: ['T20', 'T20', 'D20'], + 139: ['T20', 'T13', 'D20'], + 140: ['T20', 'T20', 'D10'], 141: ['T20', 'T19', 'D12'], - 142: ['T20', 'T18', 'D14'], + 142: ['T20', 'T14', 'D20'], 143: ['T20', 'T17', 'D16'], 144: ['T20', 'T20', 'D12'], 145: ['T20', 'T19', 'D14'], diff --git a/lib/utils/score_validator.dart b/lib/utils/score_validator.dart index f43f61a..946af26 100644 --- a/lib/utils/score_validator.dart +++ b/lib/utils/score_validator.dart @@ -11,7 +11,6 @@ abstract final class ScoreValidator { if (multiplierType == MultiplierType.outerBull) return 25; if (multiplierType == MultiplierType.miss) return 0; if (!isValidSector(rawValue)) return null; - if (multiplierType == MultiplierType.triple && rawValue == 25) return null; // no triple bull return MultiplierType.computeScore(rawValue, multiplierType); } diff --git a/test/game_logic_test.dart b/test/game_logic_test.dart index ff54ca7..70e4395 100644 --- a/test/game_logic_test.dart +++ b/test/game_logic_test.dart @@ -178,8 +178,8 @@ void main() { expect(CheckoutHelper.getSuggestion(40), ['D20']); }); - test('Bull = 50', () { - expect(CheckoutHelper.getSuggestion(50), ['Bull']); + test('Bull = S10 D20', () { + expect(CheckoutHelper.getSuggestion(50), ['S10', 'D20']); }); test('170 = T20 T20 Bull', () { @@ -190,17 +190,37 @@ void main() { expect(CheckoutHelper.getSuggestion(100), ['T20', 'D20']); }); - test('no checkout for 169', () { - expect(CheckoutHelper.getSuggestion(169), null); - }); - - test('no checkout for 1', () { - expect(CheckoutHelper.getSuggestion(1), null); - }); - - test('hasCheckout returns false for impossible scores', () { - expect(CheckoutHelper.hasCheckout(169), false); - expect(CheckoutHelper.hasCheckout(168), false); + test ('all suggestions are arithmetically correct, getSuggestion returns null and hasCheckout returns false for impossible scores', () { + for (int i = 1; i < 171; i++) { + List? output = CheckoutHelper.getSuggestion(i); + bool checkoutAvailable = CheckoutHelper.hasCheckout(i); + if (i == 1 || i == 159 || i == 162 || i == 163 || i == 165 || i == 166 || i == 168 || i == 169) { + expect(output, null); + expect(checkoutAvailable, false); + } else if (output != null) { + int sum = 0; + for (var element in output) { + if (element == 'Bull') { + sum += 50; + } else if (element == 'Outer') { + sum += 25; + } else { + final type = element[0]; + if (type == 'S') { + sum += int.parse((element.substring(1))); + } else if (type == 'D') { + sum += 2 * int.parse(element.substring(1)); + } else if (type == 'T') { + sum += 3 * int.parse(element.substring(1)); + } + } + } + expect(i, sum); + expect(checkoutAvailable, true); + } else { + fail('null checkout suggestion despite possible score, $i'); + } + } }); });