Obliczenia brydżowe (Android)
Jacek Kowalski
2015-01-18 ae5f073996625779d191002c94d6e2e608afe35a
commit | author | age
7a519e 1 package net.jacekk.bridge;
JK 2
ae5f07 3 import java.util.Arrays;
JK 4
7a519e 5 public class BridgeCompute {
ae5f07 6
JK 7     // Points for tricks (minor, major, no trump)
8     protected int tricks[] = {20, 30, 30};
7a519e 9
JK 10     // Points for [i] undertricks
11     protected int undertricks[][][] = {
12             {   // non vulnerable
ae5f07 13                     {0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650},// normal
JK 14                     {0, 100, 300, 500, 700, 900, 1100, 1300, 1500, 1700, 1900, 2100, 2300, 2500},// double
7a519e 15                     {0, 200, 600, 1000, 1400, 1800, 2200, 2600, 3000, 3400, 3800, 4200, 4600, 5000} // redouble
JK 16             },
17             {   // vulnerable
ae5f07 18                     {0, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000, 1100, 1200, 1300},// normal
JK 19                     {0, 200, 500, 800, 1100, 1400, 1700, 2000, 2300, 2600, 2900, 3200, 3500, 3800},// double
20                     {0, 400, 1000, 1600, 2200, 2800, 3400, 4000, 4600, 5200, 5800, 6400, 7000, 7600} // redouble
7a519e 21             }
JK 22     };
23
ae5f07 24     // Points required per Milton Work Point Count (from 20 up)
JK 25     protected int PC[][] = {
26             {0, 50, 70, 110, 200, 300, 350, 400, 430, 460, 490, 600, 700, 900,
27                     1000, 1100, 1200, 1400, 1400, 1400, 1400
7a519e 28             },
ae5f07 29             {0, 50, 70, 110, 290, 440, 520, 600, 630, 660, 690, 800, 1050, 1350,
JK 30                     1500, 1650, 1800, 2100, 2100, 2100, 2100
7a519e 31             }
JK 32     };
33
34     // Points required for [i] IMPs
35     protected int IMPs[] = { 0, 20, 50, 90, 130, 170, 220, 270, 320, 370, 430, 500, 600, 750, 900,
36             1100, 1300, 1500, 1750, 2000, 2250, 2500, 3000, 3500, 4000, 9999999};
37
38
39     // percent* properties are related to scoring system by Adam Królik
40     // See: http://www.gplewniak.republika.pl/strony/zapis.html
41
42     // Points received - [i] used to access row from percent variable
ae5f07 43     protected int percentPoints[][] = {
7a519e 44             {0, 50, 90, 120, 150, 180, 210, 300, 400, 430, 460, 490, 520, 800, 920, 940, 980, 990,
JK 45                     1020, 1400, 1440, 1520, 1530, 9999999}, // non vulnerable
ae5f07 46             {0, 50, 90, 120, 150, 180, 210, 500, 600, 630, 660, 690, 720, 810, 1370, 1390, 1430,
7a519e 47                     1440, 1470, 1700, 2000, 2220, 2230, 9999999} // vulnerable
JK 48     };
49
50     // Work Point Count - [i] used to access column from property percent
ae5f07 51     protected int percentPCs[] = {0, 6, 10, 16, 21, 25, 31, 35, 9999999};
7a519e 52
ae5f07 53     // Percent score per [i] - points scored, [j] - PCs had
7a519e 54     protected int percent[][] = {
JK 55             {-1, -1, -1, 50, 44, 26, 8, 0},
56             {83, 74, 65, 56, 47, 29, 11, 0},
57             {86, 77, 68, 59, 50, 32, 14, 0},
58             {89, 80, 71, 62, 53, 35, 17, 0},
59             {92, 83, 74, 65, 56, 38, 20, 2},
60             {95, 86, 77, 68, 59, 41, 23, 5},
61             {98, 89, 80, 71, 62, 44, 26, 8},
62             {100, 92, 83, 74, 65, 47, 29, 11},
63             {100, 95, 86, 77, 68, 50, 32, 14},
64             {100, 98, 89, 80, 71, 53, 35, 17},
65             {100, 100, 92, 83, 74, 56, 38, 20},
66             {100, 100, 95, 86, 77, 59, 41, 23},
67             {100, 100, 98, 89, 80, 62, 44, 26},
68             {100, 100, 100, 92, 83, 65, 47, 29},
69             {100, 100, 100, 95, 86, 68, 50, 32},
70             {100, 100, 100, 98, 89, 71, 53, 35},
71             {100, 100, 100, 100, 92, 74, 56, 38},
72             {100, 100, 100, 100, 95, 77, 59, 41},
73             {100, 100, 100, 100, 98, 80, 62, 44},
74             {100, 100, 100, 100, 100, 83, 65, 47},
75             {100, 100, 100, 100, 100, 86, 68, 50},
76             {100, 100, 100, 100, 100, 89, 71, 53},
77             {100, 100, 100, 100, 100, 100, 95, 90}
78     };
79
80     // Finds IMP score for points given (using IMPs property)
ae5f07 81     protected int getIMPs(int points) {
JK 82         int position = Arrays.binarySearch(this.IMPs, points);
83         if (position < 0) {
84             return -position - 2;
7a519e 85         }
ae5f07 86         return position;
7a519e 87     }
JK 88
89     // Finds percent score for data given (using percent* properties)
ae5f07 90     protected int getPercent(int PC, int points, int vulnerability) {
JK 91         int positionPoints = Arrays.binarySearch(this.percentPoints[vulnerability], points);
92         int positionPCs = Arrays.binarySearch(this.percentPCs, PC);
93         if (positionPoints < 0) positionPoints = -positionPoints - 2;
94         if (positionPCs < 0) positionPCs = -positionPCs - 2;
7a519e 95
ae5f07 96         return this.percent[positionPoints][positionPCs];
7a519e 97     }
JK 98
ae5f07 99     public void validateInput(BridgeInput input) throws BridgeInputException {
JK 100         if (input.bid < 0 || input.bid > 7) {
101             throw new BridgeInputException(BridgeInputException.Error.CONTRACT_LEVEL_INVALID);
102         }
103
104         if (input.suit == null) {
105             throw new BridgeInputException(BridgeInputException.Error.CONTRACT_SUIT_INVALID);
106         }
107
108         if (input.contract == null) {
109             throw new BridgeInputException(BridgeInputException.Error.CONTRACT_DOUBLE_INVALID);
110         }
111
112         if (input.PC < 0 || input.PC > 40) {
113             throw new BridgeInputException(BridgeInputException.Error.PC_INVALID);
114         }
115
116         if (input.tricks < 0 || input.tricks > 13) {
117             throw new BridgeInputException(BridgeInputException.Error.TRICKS_INVALID);
118         }
119
120         if (input.bid == 0 && input.PC < 20) {
121             throw new BridgeInputException(BridgeInputException.Error.PASSES_INVALID);
122         }
123     }
124
125     public BridgeResult getResultForInput(BridgeInput input) throws BridgeInputException {
126         validateInput(input);
127
128         int weVulnerable = (input.weVulnerable) ? 1 : 0;
129         int theyVulnerable = (input.theyVulnerable) ? 1 : 0;
130         int bid = input.bid;
131
7a519e 132         BridgeResult result = new BridgeResult();
JK 133
134         // 4 passes
ae5f07 135         if (input.bid == 0) {
JK 136             result.winners = BridgeResult.Side.They;
137             result.points = this.PC[weVulnerable][input.PC - 20];
138             result.IMPs = this.getIMPs(result.points);
139             result.percent = 100 - this.getPercent(input.PC, 0, weVulnerable);
7a519e 140             return result;
JK 141         }
142
143
ae5f07 144         int multiplier = input.contract.multiplier;
JK 145         int dbl = input.contract.tableIndex;
146         int tricks = input.tricks;
147
7a519e 148         // Result in points
ae5f07 149         int points;
JK 150         // Points for tricks bid
151         int pointsForTricksBid;
7a519e 152         // Result minus points required, according to PC property
JK 153         int pointsForScoring;
154
155         // Number of overtricks (or undertricks if negative)
156         int additionalTricks = tricks - 6 - bid;
157
158         // Contract made
159         if (additionalTricks >= 0) {
ae5f07 160             pointsForTricksBid = this.tricks[input.suit.tableIndex] * bid * multiplier;
JK 161             if (input.suit.equals(BridgeInput.Suit.NOTRUMP)) {
162                 // First trick in no trump game is worth 10 points more
163                 pointsForTricksBid += 10 * multiplier;
164             }
165             points = pointsForTricksBid;
166
167             // Add points for overtricks
168
7a519e 169             // Ordinary contract
ae5f07 170             if (input.contract.equals(BridgeInput.Contract.NORMAL)) {
JK 171                 points += this.tricks[input.suit.tableIndex] * additionalTricks;
7a519e 172             }
JK 173             // Contract doubled/redoubled
174             else {
ae5f07 175                 points += (!input.weVulnerable ? 50 : 100) * multiplier * additionalTricks;
7a519e 176
JK 177                 // Bonus for winning doubled/redoubled contract
ae5f07 178                 points += 25 * multiplier;
7a519e 179             }
JK 180
181             if (bid == 6) {
182                 // Bonus for small slam
ae5f07 183                 points += (!input.weVulnerable ? 500 : 750);
7a519e 184             } else if (bid == 7) {
JK 185                 // Bonus for grand slam
ae5f07 186                 points += (!input.weVulnerable ? 1000 : 1500);
7a519e 187             }
JK 188
ae5f07 189             if (pointsForTricksBid >= 100) {
7a519e 190                 // Bonus for game
ae5f07 191                 points += (!input.weVulnerable ? 300 : 500);
7a519e 192             } else {
JK 193                 // Bonus for part-game
ae5f07 194                 points += 50;
7a519e 195             }
JK 196         }
197         // Contract defeated
198         else {
199             // Points for undertricks (for defending side)
ae5f07 200             points = -1 * this.undertricks[weVulnerable][dbl][-1 * additionalTricks];
7a519e 201         }
JK 202
203         // Deduct points required
ae5f07 204         if (input.PC >= 20) {
JK 205             pointsForScoring = points - this.PC[weVulnerable][input.PC - 20];
206         } else {
207             pointsForScoring = points + this.PC[theyVulnerable][20 - input.PC];
208         }
7a519e 209
JK 210         // Score for defeaters
211         if (pointsForScoring < 0) {
ae5f07 212             result.winners = BridgeResult.Side.They;
JK 213             result.pointsBefore = -1 * points;
7a519e 214             result.points = -1 * pointsForScoring;
ae5f07 215
JK 216             if (points < 0) {
217                 result.percent = getPercent(40 - input.PC, -points, theyVulnerable);
7a519e 218             } else {
ae5f07 219                 result.percent = 100 - getPercent(input.PC, points, weVulnerable);
7a519e 220             }
JK 221         }
222         // Score for declarers
223         else {
ae5f07 224             result.winners = BridgeResult.Side.We;
JK 225             result.pointsBefore = points;
7a519e 226             result.points = pointsForScoring;
ae5f07 227
JK 228             if (points > 0) {
229                 result.percent = getPercent(input.PC, points, weVulnerable);
7a519e 230             } else {
ae5f07 231                 result.percent = 100 - getPercent(40 - input.PC, -points, theyVulnerable);
7a519e 232             }
JK 233         }
234
ae5f07 235         result.IMPs = getIMPs(result.points);
JK 236
237
7a519e 238         return result;
JK 239     }
240 }