summaryrefslogtreecommitdiff
path: root/bin/lib/OsikaEvaluator.php
diff options
context:
space:
mode:
Diffstat (limited to 'bin/lib/OsikaEvaluator.php')
-rw-r--r--bin/lib/OsikaEvaluator.php504
1 files changed, 252 insertions, 252 deletions
diff --git a/bin/lib/OsikaEvaluator.php b/bin/lib/OsikaEvaluator.php
index c20816f..474cffe 100644
--- a/bin/lib/OsikaEvaluator.php
+++ b/bin/lib/OsikaEvaluator.php
@@ -4,286 +4,286 @@ require_once('OsikaParser.php');
class OsikaEvaluator {
- private $_hand;
+ private $_hand;
- public function __construct($hand = NULL) {
- if ($hand) {
- $this->setHand($hand);
- }
- }
-
- public function setHand($hand) {
- $parser = new OsikaParser($hand);
- $this->_hand = $parser->parse();
- }
-
- private static $_honorCounts = array();
- private function _countHonors($suit, $major = FALSE) {
- if (!isset(self::$_honorCounts[$suit])) {
- self::$_honorCounts[$suit] = array(NULL, NULL);
- }
- if (self::$_honorCounts[$suit][$major] === NULL) {
- $dummy = array();
- self::$_honorCounts[$suit][$major] = preg_match_all($major ? '/a|k|q/' : '/a|k|q|j/', $suit, $dummy);
- }
- return self::$_honorCounts[$suit][$major];
- }
+ public function __construct($hand = NULL) {
+ if ($hand) {
+ $this->setHand($hand);
+ }
+ }
- private static $_cardHonorTricks = array(
- 'a' => 1.125,
- 'k' => 0.8125,
- 'q' => 0.4375,
- 'j' => 0.125
- );
- private function _honorTricks($suit) {
- // only 3 highest cards in the suit holding count towards honor tricks
- $suit = substr($suit, 0, 3);
+ public function setHand($hand) {
+ $parser = new OsikaParser($hand);
+ $this->_hand = $parser->parse();
+ }
- $cards = self::$_cardHonorTricks;
- // only count Jack if it's the highest card in suit
- if (strpos($suit, 'j') !== 0) {
- $cards = array_slice($cards, 0, 3);
- }
+ private static $_honorCounts = array();
+ private function _countHonors($suit, $major = FALSE) {
+ if (!isset(self::$_honorCounts[$suit])) {
+ self::$_honorCounts[$suit] = array(NULL, NULL);
+ }
+ if (self::$_honorCounts[$suit][$major] === NULL) {
+ $dummy = array();
+ self::$_honorCounts[$suit][$major] = preg_match_all($major ? '/a|k|q/' : '/a|k|q|j/', $suit, $dummy);
+ }
+ return self::$_honorCounts[$suit][$major];
+ }
- $ret = 0;
- foreach ($cards as $card => $value) {
- $ret += substr_count($suit, $card) * $value;
- }
- return $ret;
- }
+ private static $_cardHonorTricks = array(
+ 'a' => 1.125,
+ 'k' => 0.8125,
+ 'q' => 0.4375,
+ 'j' => 0.125
+ );
+ private function _honorTricks($suit) {
+ // only 3 highest cards in the suit holding count towards honor tricks
+ $suit = substr($suit, 0, 3);
- private function _honorTrickCorrections($suit) {
- // only 3 highest cards in the suit holding count towards honor tricks
- $suit = substr($suit, 0, 3);
- $count = $this->_countHonors($suit);
- // HH = 1/4 trick; HHH = 1/2 trick
- return ($count < 2) ? 0 : $count * 0.25;
- }
+ $cards = self::$_cardHonorTricks;
+ // only count Jack if it's the highest card in suit
+ if (strpos($suit, 'j') !== 0) {
+ $cards = array_slice($cards, 0, 3);
+ }
- private function _honorTrickSupportCorrections($suit) {
- $ret = 0;
- // every 10 within 4+ suit with any of the AKQ = 1/8 of a trick
- if (strlen($suit) > 3 && strpos($suit, 't') !== FALSE && $this->_countHonors($suit, TRUE)) {
- $ret += 0.125;
- }
- // every 109 = 1/16 of a trick
- if (strpos($suit, 't9') !== FALSE) {
- $ret += 0.0625;
- }
- return $ret;
- }
+ $ret = 0;
+ foreach ($cards as $card => $value) {
+ $ret += substr_count($suit, $card) * $value;
+ }
+ return $ret;
+ }
- private function _honorTrickShortCorrections($suit) {
- $length = strlen($suit);
- // either nothing to subtract from or no need to
- if (!$length || $length > 2) {
- return 0;
- }
- $count = $this->_countHonors($suit);
- if (!$count) {
- return 0;
- }
- // H sec = -1/8 of a trick; Hx = -1/16 of a trick; HH sec = -1/8 of a trick
- return $count * (($length === 1) ? -0.125 : -0.0625);
- }
+ private function _honorTrickCorrections($suit) {
+ // only 3 highest cards in the suit holding count towards honor tricks
+ $suit = substr($suit, 0, 3);
+ $count = $this->_countHonors($suit);
+ // HH = 1/4 trick; HHH = 1/2 trick
+ return ($count < 2) ? 0 : $count * 0.25;
+ }
- private static $_lengthDistributionTricks = array(
- 4 => 0.4375,
- 5 => 1.5,
- 6 => 2.75,
- 7 => 3.9375
- );
- private function _distributionTricks($suit) {
- $length = strlen($suit);
- if ($length < 4) {
- return 0;
- }
- if ($length >= 8) {
- return $length - 3;
- }
- return self::$_lengthDistributionTricks[$length];
- }
+ private function _honorTrickSupportCorrections($suit) {
+ $ret = 0;
+ // every 10 within 4+ suit with any of the AKQ = 1/8 of a trick
+ if (strlen($suit) > 3 && strpos($suit, 't') !== FALSE && $this->_countHonors($suit, TRUE)) {
+ $ret += 0.125;
+ }
+ // every 109 = 1/16 of a trick
+ if (strpos($suit, 't9') !== FALSE) {
+ $ret += 0.0625;
+ }
+ return $ret;
+ }
- private function _quickTricks($hand) {
- $hand = '|'.implode('|', $hand);
- // aces and kings contribute towards quick tricks
- $highCards = substr_count($hand, 'a') + substr_count($hand, 'k');
- // queens and jacks contribute against, but we don't count unsupported jacks, because of how they count towards honor tricks in the first place
- $lowCards = substr_count($hand, 'q') + substr_count($hand, 'j') - substr_count($hand, '|j');
- $difference = $highCards - $lowCards;
- // difference of:
- // +3 or more = 1/8
- // +2 = 1/16
- // +1 to -1 = 0
- // -2 = -1/16
- // -3 or less = -1/8
- if (abs($difference) <= 1) {
- return 0;
- }
- if ($difference > 2) {
- return 0.125;
- }
- if ($difference > 1) {
- return 0.0625;
- }
- if ($difference < -2) {
- return -0.125;
- }
- if ($difference < -1) {
- return -0.0625;
- }
- }
+ private function _honorTrickShortCorrections($suit) {
+ $length = strlen($suit);
+ // either nothing to subtract from or no need to
+ if (!$length || $length > 2) {
+ return 0;
+ }
+ $count = $this->_countHonors($suit);
+ if (!$count) {
+ return 0;
+ }
+ // H sec = -1/8 of a trick; Hx = -1/16 of a trick; HH sec = -1/8 of a trick
+ return $count * (($length === 1) ? -0.125 : -0.0625);
+ }
- private function _middleCardCorrections($hand) {
- // count only 10's and 9's in 3+ card suits
- $nonshort = '';
- foreach ($hand as $suit) {
- if (strlen($suit) >= 3) {
- $nonshort .= $suit;
+ private static $_lengthDistributionTricks = array(
+ 4 => 0.4375,
+ 5 => 1.5,
+ 6 => 2.75,
+ 7 => 3.9375
+ );
+ private function _distributionTricks($suit) {
+ $length = strlen($suit);
+ if ($length < 4) {
+ return 0;
+ }
+ if ($length >= 8) {
+ return $length - 3;
}
- }
- // statistically, we should have 2 of those
- // but we're not counting short suits and some long suit 10 configurations
- // so the par for the course is 1 middle card
- $dummy = array(); // this is humiliating
- $count = preg_match_all('/t|9/', $nonshort, $dummy) - 1;
- // if we're better than that single middle card -> 1/16 of a trick
- // if we're worse -> -1/16
- return max(-0.0625, min(0.0625, $count * 0.0625));
- }
+ return self::$_lengthDistributionTricks[$length];
+ }
- private function _shortSuitCorrections($distribution) {
- $shortSuits = array();
- foreach ($distribution as $suit) {
- // short suit is a 3- card suit here
- if ($suit <= 3) {
- $shortSuits[] = $suit;
+ private function _quickTricks($hand) {
+ $hand = '|'.implode('|', $hand);
+ // aces and kings contribute towards quick tricks
+ $highCards = substr_count($hand, 'a') + substr_count($hand, 'k');
+ // queens and jacks contribute against, but we don't count unsupported jacks, because of how they count towards honor tricks in the first place
+ $lowCards = substr_count($hand, 'q') + substr_count($hand, 'j') - substr_count($hand, '|j');
+ $difference = $highCards - $lowCards;
+ // difference of:
+ // +3 or more = 1/8
+ // +2 = 1/16
+ // +1 to -1 = 0
+ // -2 = -1/16
+ // -3 or less = -1/8
+ if (abs($difference) <= 1) {
+ return 0;
}
- }
- // the correction only applies if we're having 2 or more short suits
- if (count($shortSuits) < 2) {
- return 0;
- }
- sort($shortSuits);
- // if the shortest short suits are 3-0, 3-1 or 2-0, we add 1/16 of a trick
- $diff = $shortSuits[1] - $shortSuits[0];
- return ($diff > 1) ? 0.0625 : 0;
- }
+ if ($difference > 2) {
+ return 0.125;
+ }
+ if ($difference > 1) {
+ return 0.0625;
+ }
+ if ($difference < -2) {
+ return -0.125;
+ }
+ if ($difference < -1) {
+ return -0.0625;
+ }
+ }
- private function _majorSuitCorrections($distribution) {
- // at least 8 cards in majors...
- if ($distribution['s'] + $distribution['h'] >= 8) {
- // ...and at least 3 cards in each major...
- if ($distribution['h'] > 2 && $distribution['h'] > 2) {
- // ...constitute a 1/16 of a trick correction
- return 0.0625;
+ private function _middleCardCorrections($hand) {
+ // count only 10's and 9's in 3+ card suits
+ $nonshort = '';
+ foreach ($hand as $suit) {
+ if (strlen($suit) >= 3) {
+ $nonshort .= $suit;
+ }
}
- }
- return 0;
- }
+ // statistically, we should have 2 of those
+ // but we're not counting short suits and some long suit 10 configurations
+ // so the par for the course is 1 middle card
+ $dummy = array(); // this is humiliating
+ $count = preg_match_all('/t|9/', $nonshort, $dummy) - 1;
+ // if we're better than that single middle card -> 1/16 of a trick
+ // if we're worse -> -1/16
+ return max(-0.0625, min(0.0625, $count * 0.0625));
+ }
- // I honestly have no idea what the hell's going on below.
- private function _localizationCorrections($result, $distribution) {
- $strength = array();
- $length = array();
- foreach ($result['lh'] as $index => $value) {
- if (strlen($index) === 1) {
- if ($distribution[$index] >= 3) {
- if (isset($strength[$distribution[$index]])) {
- $strength[$distribution[$index]] += ($result['lh'][$index]+$result['lh_plus'][$index]+$result['lh_pod'][$index]+$result['lh_short'][$index]);
- }
- else {
- $strength[$distribution[$index]] = ($result['lh'][$index]+$result['lh_plus'][$index]+$result['lh_pod'][$index]+$result['lh_short'][$index]);
- }
- if (isset($length[$distribution[$index]])) {
- $length[$distribution[$index]] += $distribution[$index];
- }
- else {
- $length[$distribution[$index]] = $distribution[$index];
- }
- }
+ private function _shortSuitCorrections($distribution) {
+ $shortSuits = array();
+ foreach ($distribution as $suit) {
+ // short suit is a 3- card suit here
+ if ($suit <= 3) {
+ $shortSuits[] = $suit;
+ }
}
- }
- ksort($strength);
- ksort($length);
- $sumLength = array_sum($length);
- $sumStrength = array_sum($strength);
- $longestDiff = end($strength)-$sumStrength*end($length)/$sumLength;
- $shortestDiff = reset($strength)-$sumStrength*reset($length)/$sumLength;
- if (abs($longestDiff) > 0.5) {
- if (abs($longestDiff) > 1) {
- return 0.25*(abs($longestDiff)/$longestDiff);
+ // the correction only applies if we're having 2 or more short suits
+ if (count($shortSuits) < 2) {
+ return 0;
}
- else {
- return 0.125*(abs($longestDiff)/$longestDiff);
+ sort($shortSuits);
+ // if the shortest short suits are 3-0, 3-1 or 2-0, we add 1/16 of a trick
+ $diff = $shortSuits[1] - $shortSuits[0];
+ return ($diff > 1) ? 0.0625 : 0;
+ }
+
+ private function _majorSuitCorrections($distribution) {
+ // at least 8 cards in majors...
+ if ($distribution['s'] + $distribution['h'] >= 8) {
+ // ...and at least 3 cards in each major...
+ if ($distribution['h'] > 2 && $distribution['h'] > 2) {
+ // ...constitute a 1/16 of a trick correction
+ return 0.0625;
+ }
+ }
+ return 0;
+ }
+
+ // I honestly have no idea what the hell's going on below.
+ private function _localizationCorrections($result, $distribution) {
+ $strength = array();
+ $length = array();
+ foreach ($result['lh'] as $index => $value) {
+ if (strlen($index) === 1) {
+ if ($distribution[$index] >= 3) {
+ if (isset($strength[$distribution[$index]])) {
+ $strength[$distribution[$index]] += ($result['lh'][$index]+$result['lh_plus'][$index]+$result['lh_pod'][$index]+$result['lh_short'][$index]);
+ }
+ else {
+ $strength[$distribution[$index]] = ($result['lh'][$index]+$result['lh_plus'][$index]+$result['lh_pod'][$index]+$result['lh_short'][$index]);
+ }
+ if (isset($length[$distribution[$index]])) {
+ $length[$distribution[$index]] += $distribution[$index];
+ }
+ else {
+ $length[$distribution[$index]] = $distribution[$index];
+ }
+ }
+ }
}
- }
- if (abs($shortestDiff) > 0.5) {
- if (abs($shortestDiff) > 1) {
- return -0.125*(abs($shortestDiff)/$shortestDiff);
+ ksort($strength);
+ ksort($length);
+ $sumLength = array_sum($length);
+ $sumStrength = array_sum($strength);
+ $longestDiff = end($strength)-$sumStrength*end($length)/$sumLength;
+ $shortestDiff = reset($strength)-$sumStrength*reset($length)/$sumLength;
+ if (abs($longestDiff) > 0.5) {
+ if (abs($longestDiff) > 1) {
+ return 0.25*(abs($longestDiff)/$longestDiff);
+ }
+ else {
+ return 0.125*(abs($longestDiff)/$longestDiff);
+ }
}
- else {
- return -0.0625*(abs($shortestDiff)/$shortestDiff);
+ if (abs($shortestDiff) > 0.5) {
+ if (abs($shortestDiff) > 1) {
+ return -0.125*(abs($shortestDiff)/$shortestDiff);
+ }
+ else {
+ return -0.0625*(abs($shortestDiff)/$shortestDiff);
+ }
}
- }
- return 0;
- }
+ return 0;
+ }
- private static $_suits = array('s','h','d','c');
- public function evaluate() {
- $result = array();
- $result['lh'] = array();
- $result['lh_plus'] = array();
- $result['lh_pod'] = array();
- $result['lh_short'] = array();
- $result['lu'] = array();
- foreach ($this->_hand as $ind => $suit) {
- $suitChar = self::$_suits[$ind];
- $result['lh'][$suitChar] = $this->_honorTricks($suit);
- $result['lh_plus'][$suitChar] = $this->_honorTrickCorrections($suit);
- $result['lh_pod'][$suitChar] = $this->_honorTrickSupportCorrections($suit);
- $result['lh_short'][$suitChar] = $this->_honorTrickShortCorrections($suit);
- $result['lu'][$suitChar] = $this->_distributionTricks($suit);
- }
- $result['lh']['total'] = array_sum($result['lh']);
- $result['lh_plus']['total'] = array_sum($result['lh_plus']);
- $result['lh_pod']['total'] = array_sum($result['lh_pod']);
- $result['lh_short']['total'] = array_sum($result['lh_short']);
- $result['lu']['total'] = array_sum($result['lu']);
+ private static $_suits = array('s','h','d','c');
+ public function evaluate() {
+ $result = array();
+ $result['lh'] = array();
+ $result['lh_plus'] = array();
+ $result['lh_pod'] = array();
+ $result['lh_short'] = array();
+ $result['lu'] = array();
+ foreach ($this->_hand as $ind => $suit) {
+ $suitChar = self::$_suits[$ind];
+ $result['lh'][$suitChar] = $this->_honorTricks($suit);
+ $result['lh_plus'][$suitChar] = $this->_honorTrickCorrections($suit);
+ $result['lh_pod'][$suitChar] = $this->_honorTrickSupportCorrections($suit);
+ $result['lh_short'][$suitChar] = $this->_honorTrickShortCorrections($suit);
+ $result['lu'][$suitChar] = $this->_distributionTricks($suit);
+ }
+ $result['lh']['total'] = array_sum($result['lh']);
+ $result['lh_plus']['total'] = array_sum($result['lh_plus']);
+ $result['lh_pod']['total'] = array_sum($result['lh_pod']);
+ $result['lh_short']['total'] = array_sum($result['lh_short']);
+ $result['lu']['total'] = array_sum($result['lu']);
- $result['lsz'] = array('total' => $this->_quickTricks($this->_hand));
- $result['lu_plus'] = array('total' => $this->_middleCardCorrections($this->_hand));
+ $result['lsz'] = array('total' => $this->_quickTricks($this->_hand));
+ $result['lu_plus'] = array('total' => $this->_middleCardCorrections($this->_hand));
- $distribution = array_combine(self::$_suits, array_map('strlen', $this->_hand));
- $result['short_suit'] = array('total' => $this->_shortSuitCorrections($distribution));
- $result['major_suit'] = array('total' => $this->_majorSuitCorrections($distribution));
+ $distribution = array_combine(self::$_suits, array_map('strlen', $this->_hand));
+ $result['short_suit'] = array('total' => $this->_shortSuitCorrections($distribution));
+ $result['major_suit'] = array('total' => $this->_majorSuitCorrections($distribution));
- $result['l10n'] = array('total' => $this->_localizationCorrections($result, $distribution));
+ $result['l10n'] = array('total' => $this->_localizationCorrections($result, $distribution));
- $subtotal = array();
- $lhSubtotal = array();
- $total = 0;
- foreach ($result as $category => $factor) {
- if (count($factor) === 5) {
- foreach ($factor as $index => $subt) {
- if (!isset($subtotal[$index])) {
- $subtotal[$index] = 0;
- $lhSubtotal[$index] = 0;
- }
- $subtotal[$index] += $subt;
- if ($category !== 'lu') {
- $lhSubtotal[$index] += $subt;
- }
- }
+ $subtotal = array();
+ $lhSubtotal = array();
+ $total = 0;
+ foreach ($result as $category => $factor) {
+ if (count($factor) === 5) {
+ foreach ($factor as $index => $subt) {
+ if (!isset($subtotal[$index])) {
+ $subtotal[$index] = 0;
+ $lhSubtotal[$index] = 0;
+ }
+ $subtotal[$index] += $subt;
+ if ($category !== 'lu') {
+ $lhSubtotal[$index] += $subt;
+ }
+ }
+ }
+ $total += $factor['total'];
}
- $total += $factor['total'];
- }
- $result['lh_subtotal'] = $lhSubtotal;
- $result['subtotal'] = $subtotal;
- $result['total'] = array('total' => $total);
+ $result['lh_subtotal'] = $lhSubtotal;
+ $result['subtotal'] = $subtotal;
+ $result['total'] = array('total' => $total);
- return $result;
- }
+ return $result;
+ }
}