| 997 | } |
| 998 | |
| 999 | auto Moves::RegisterHit(const int trick, const int relHand) -> void { |
| 1000 | const MovePlyType &list = moveList[trick][relHand]; |
| 1001 | |
| 1002 | const int findex = static_cast<int>(lastCall[trick][relHand]); |
| 1003 | const int len = list.last + 1; |
| 1004 | |
| 1005 | // Internal invariant: lastCall must be initialized before RegisterHit |
| 1006 | assert(findex != -1 && "RegisterHit: lastCall not initialized"); |
| 1007 | |
| 1008 | const int curr = list.current; |
| 1009 | // Internal invariant: current must be within valid range [1, len] |
| 1010 | assert(curr >= 1 && curr <= len && "RegisterHit: current out of bounds"); |
| 1011 | |
| 1012 | const int moveSuit = list.move[curr - 1].suit; |
| 1013 | int numSuit = 0; |
| 1014 | int numSeen = 0; |
| 1015 | |
| 1016 | for (int i = 0; i < len; i++) { |
| 1017 | if (list.move[i].suit == moveSuit) { |
| 1018 | numSuit++; |
| 1019 | if (i == curr - 1) |
| 1020 | numSeen = numSuit; |
| 1021 | } |
| 1022 | } |
| 1023 | |
| 1024 | // Now we know enough to update the statistics tables. |
| 1025 | |
| 1026 | trickTable[trick][relHand].count++; |
| 1027 | trickTable[trick][relHand].sumHits += curr; |
| 1028 | trickTable[trick][relHand].sumLengths += len; |
| 1029 | |
| 1030 | trickSuitTable[trick][relHand].count++; |
| 1031 | trickSuitTable[trick][relHand].sumHits += numSeen; |
| 1032 | trickSuitTable[trick][relHand].sumLengths += numSuit; |
| 1033 | |
| 1034 | Moves::UpdateStatsEntry(trickDetailTable[trick][relHand], findex, curr, len); |
| 1035 | |
| 1036 | Moves::UpdateStatsEntry(trickDetailSuitTable[trick][relHand], findex, numSeen, |
| 1037 | numSuit); |
| 1038 | |
| 1039 | Moves::UpdateStatsEntry(trickFuncTable, findex, curr, len); |
| 1040 | |
| 1041 | Moves::UpdateStatsEntry(trickFuncSuitTable, findex, numSeen, numSuit); |
| 1042 | } |
| 1043 | |
| 1044 | auto Moves::AverageString(const moveStatType &stat) const -> string { |
| 1045 | stringstream ss; |