diff options
-rw-r--r-- | bin/lib/OsikaEvaluator.php | 504 | ||||
-rw-r--r-- | bin/lib/OsikaParser.php | 226 | ||||
-rwxr-xr-x | bin/osika | 199 |
3 files changed, 464 insertions, 465 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; + } } diff --git a/bin/lib/OsikaParser.php b/bin/lib/OsikaParser.php index 75fc302..d2046f4 100644 --- a/bin/lib/OsikaParser.php +++ b/bin/lib/OsikaParser.php @@ -5,111 +5,111 @@ **/ class OsikaParser { - private $_hand; + private $_hand; - /** - * Constructor for the parser class - * @param $hand (optional) hand to parse - **/ - public function __construct($hand = NULL) { - $this->setHand($hand); - } + /** + * Constructor for the parser class + * @param $hand (optional) hand to parse + **/ + public function __construct($hand = NULL) { + $this->setHand($hand); + } - /** - * Sets the hand string to parse - * @param $hand string of xxxx|xxx|xxx|xxx format - **/ - public function setHand($hand) { - $this->_hand = $hand; - } - - /** - * Card comparison function - * @param $cardA, $cardB - characters denoting cards - * @return 1 or -1, as usort() expects - **/ - private function _sort($cardA, $cardB) { - // aces first - if ($cardA == 'a') { - return -1; - } - // ...than kings... - if ($cardA == 'k') { - return ($cardB == 'a') ? 1 : -1; - } - // ...queens... - if ($cardA == 'q') { - return (in_array($cardB, array('a', 'k'))) ? 1 : -1; - } - // ...jacks... - if ($cardA == 'j') { - return (in_array($cardB, array('a', 'k', 'q'))) ? 1 : -1; - } - // ...tens... - if ($cardA == 't') { - return (in_array($cardB, array('a', 'k', 'q', 'j'))) ? 1 : -1; - } - // ... and nines - if ($cardA == '9') { - return (in_array($cardB, array('a', 'k', 'q', 'j', 't'))) ? 1 : -1; - } - // anything else goes last, as it was - return 1; - } + /** + * Sets the hand string to parse + * @param $hand string of xxxx|xxx|xxx|xxx format + **/ + public function setHand($hand) { + $this->_hand = $hand; + } - /** - * Suit sorting function. Uses OsikaParser::_sort as user-defined sort function for the exploded string. - **/ - private function _sortSuit(&$suit) { - $temp = str_split($suit); - usort($temp, array($this, '_sort')); - $suit = implode('', $temp); - } + /** + * Card comparison function + * @param $cardA, $cardB - characters denoting cards + * @return 1 or -1, as usort() expects + **/ + private function _sort($cardA, $cardB) { + // aces first + if ($cardA == 'a') { + return -1; + } + // ...than kings... + if ($cardA == 'k') { + return ($cardB == 'a') ? 1 : -1; + } + // ...queens... + if ($cardA == 'q') { + return (in_array($cardB, array('a', 'k'))) ? 1 : -1; + } + // ...jacks... + if ($cardA == 'j') { + return (in_array($cardB, array('a', 'k', 'q'))) ? 1 : -1; + } + // ...tens... + if ($cardA == 't') { + return (in_array($cardB, array('a', 'k', 'q', 'j'))) ? 1 : -1; + } + // ... and nines + if ($cardA == '9') { + return (in_array($cardB, array('a', 'k', 'q', 'j', 't'))) ? 1 : -1; + } + // anything else goes last, as it was + return 1; + } + + /** + * Suit sorting function. Uses OsikaParser::_sort as user-defined sort function for the exploded string. + **/ + private function _sortSuit(&$suit) { + $temp = str_split($suit); + usort($temp, array($this, '_sort')); + $suit = implode('', $temp); + } - /** - * Where the magic happens. - **/ - public function parse() { - if (!$this->_hand) { - throw new OsikaParserException('Brak podanej ręki', OsikaParserException::NO_HAND); - } - // input is case-insensitive - $this->_hand = strtolower($this->_hand); - // allow (and interpret) Polish figures abbrevs. and "10" as Ten - $this->_hand = strtr($this->_hand, - array( - '10' => 't', - 'w' => 'j', - 'd' => 'q')); - // strip whitespace - $this->_hand = preg_replace('/\s/', '', $this->_hand); - $suits = explode('|', $this->_hand); - // check for invalid number of suits suits in the hand - if (count($suits) !== 4) { - throw new OsikaParserException('Ręka nie zawiera 4 kolorów', OsikaParserException::INVALID_SUIT_COUNT); - } - $cardCount = 0; - foreach ($suits as &$suit) { - // check for invalid characters - if (preg_match('/[^akqjtx2-9]/', $suit)) { - throw new OsikaParserException('Kolor '.$suit.' zawiera nieprawidłowe znaki', OsikaParserException::INVALID_CHARS); + /** + * Where the magic happens. + **/ + public function parse() { + if (!$this->_hand) { + throw new OsikaParserException('Brak podanej ręki', OsikaParserException::NO_HAND); + } + // input is case-insensitive + $this->_hand = strtolower($this->_hand); + // allow (and interpret) Polish figures abbrevs. and "10" as Ten + $this->_hand = strtr($this->_hand, + array( + '10' => 't', + 'w' => 'j', + 'd' => 'q')); + // strip whitespace + $this->_hand = preg_replace('/\s/', '', $this->_hand); + $suits = explode('|', $this->_hand); + // check for invalid number of suits suits in the hand + if (count($suits) !== 4) { + throw new OsikaParserException('Ręka nie zawiera 4 kolorów', OsikaParserException::INVALID_SUIT_COUNT); + } + $cardCount = 0; + foreach ($suits as &$suit) { + // check for invalid characters + if (preg_match('/[^akqjtx2-9]/', $suit)) { + throw new OsikaParserException('Kolor '.$suit.' zawiera nieprawidłowe znaki', OsikaParserException::INVALID_CHARS); + } + // check for duplicate cards + foreach (array('a', 'k', 'q', 'j', 't', '9') as $honor) { + if (substr_count($suit, $honor) > 1) { + throw new OsikaParserException('Kolor '.$suit.' zawiera zduplikowany honor (lub 9)', OsikaParserException::DUPLICATE_CHARS); + } + } + $this->_sortSuit($suit); + $cardCount += strlen($suit); } - // check for duplicate cards - foreach (array('a', 'k', 'q', 'j', 't', '9') as $honor) { - if (substr_count($suit, $honor) > 1) { - throw new OsikaParserException('Kolor '.$suit.' zawiera zduplikowany honor (lub 9)', OsikaParserException::DUPLICATE_CHARS); - } + unset($suit); + // check for wrong card count + if ($cardCount !== 13) { + throw new OsikaParserException('Ręka nie zawiera 13 kart', OsikaParserException::INVALID_CARD_COUNT); } - $this->_sortSuit($suit); - $cardCount += strlen($suit); - } - unset($suit); - // check for wrong card count - if ($cardCount !== 13) { - throw new OsikaParserException('Ręka nie zawiera 13 kart', OsikaParserException::INVALID_CARD_COUNT); - } - return $suits; - } + return $suits; + } } @@ -118,21 +118,21 @@ class OsikaParser { **/ class OsikaParserException extends Exception { - const NO_HAND = 1; // empty (or equivalent) string provided - const INVALID_SUIT_COUNT = 2; // the hand does not contain 4 suit (i.e. 3 "|" chars) - const INVALID_CHARS = 3; // the hand contains characters that make no sense - const DUPLICATE_CHARS = 4; // the hand contains duplicate honors (or 9) - const INVALID_CARD_COUNT = 5; // the hand does not contain 13 cards + const NO_HAND = 1; // empty (or equivalent) string provided + const INVALID_SUIT_COUNT = 2; // the hand does not contain 4 suit (i.e. 3 "|" chars) + const INVALID_CHARS = 3; // the hand contains characters that make no sense + const DUPLICATE_CHARS = 4; // the hand contains duplicate honors (or 9) + const INVALID_CARD_COUNT = 5; // the hand does not contain 13 cards - /* - Should we check if the hand contains exactly 13 cards? - I don't think the algorithm technically relies on the hand being complete. - But does the evaluation stand for incomplete hands? - E.g. if we played the first 7 tricks and are left with AK AK AK ==, - do all the quick tricks, short honor and grouped honor evaluations compute correctly? - Or even make sense? - */ + /* + Should we check if the hand contains exactly 13 cards? + I don't think the algorithm technically relies on the hand being complete. + But does the evaluation stand for incomplete hands? + E.g. if we played the first 7 tricks and are left with AK AK AK ==, + do all the quick tricks, short honor and grouped honor evaluations compute correctly? + Or even make sense? + */ }; -?>
\ No newline at end of file +?> @@ -1,40 +1,39 @@ #!/usr/bin/env php <?php -class Osika -{ - - private static $suitHeaders = array( - 'c' => '♣', - 'd' => '♦', - 'h' => '♥', - 's' => '♠', - 'total' => 'Σ' - ); - private static $catHeaders = array( - 'lh' => "Honory\t", - 'lh_plus' => 'Zgrupowania', - 'lh_10' => 'Podwiązania', - 'lh_short' => 'Krótkie honory', - 'lh_subtotal' => 'Lewy honorowe', - 'lu' => 'Lewy układowe', - 'subtotal' => "Razem\t", - 'lsz' => 'Lewy szybkie', - 'lu_plus' => 'Wysokie blotki', - 'short_suit' => 'Kolory krótkie', - 'major_suit' => 'Kolory starsze', - 'l10n' => 'Lokalizacja', - 'total' => "Łącznie\t" - ); - - - public static function printHelp() { - print "OSiKa, v1.0.0, autor: M. Klichowicz (mkl) +class Osika { + + private static $suitHeaders = array( + 'c' => '♣', + 'd' => '♦', + 'h' => '♥', + 's' => '♠', + 'total' => 'Σ' + ); + private static $catHeaders = array( + 'lh' => "Honory\t", + 'lh_plus' => 'Zgrupowania', + 'lh_10' => 'Podwiązania', + 'lh_short' => 'Krótkie honory', + 'lh_subtotal' => 'Lewy honorowe', + 'lu' => 'Lewy układowe', + 'subtotal' => "Razem\t", + 'lsz' => 'Lewy szybkie', + 'lu_plus' => 'Wysokie blotki', + 'short_suit' => 'Kolory krótkie', + 'major_suit' => 'Kolory starsze', + 'l10n' => 'Lokalizacja', + 'total' => "Łącznie\t" + ); + + + public static function printHelp() { + print "OSiKa, v1.0.0, autor: M. Klichowicz (mkl) Program do analizy siły ręki brydżowej metodami algorytmów licytacji naturalnej wg Łukasza Sławińskiego. Sposób użycia: - + php osika [OPCJE] KARTY KARTY @@ -53,48 +52,48 @@ OPCJE Lista (rozdzielonych przecinkami) składowych łącznej siły ręki, które program ma wyświetlić. Domyślna wartość: all. Dostępne wartości:"; - foreach (self::$catHeaders as $cat => $header) { - print " + foreach (self::$catHeaders as $cat => $header) { + print " $cat: $header"; - } - print " + } + print " -s KOLORY Lista (rozdzielonych przecinkami) kolorów, dla których składowe program ma wyświetlić. Możliwe wartości: s, h, d, c, total, all. Domyślna wartość: all "; - } - - public static function printTable($output, $categories, $suits, $raw = FALSE) { - if (!$raw) { - print "\t\t"; - foreach ($suits as $suit) { - if (isset(self::$suitHeaders[$suit])) { - print self::$suitHeaders[$suit]; - } - print "\t"; - } - print "\n"; - } - foreach ($categories as $cat) { + } + + public static function printTable($output, $categories, $suits, $raw = FALSE) { if (!$raw) { - if (isset(self::$catHeaders[$cat])) { - print self::$catHeaders[$cat]; - } - print "\t"; + print "\t\t"; + foreach ($suits as $suit) { + if (isset(self::$suitHeaders[$suit])) { + print self::$suitHeaders[$suit]; + } + print "\t"; + } + print "\n"; } - foreach ($suits as $suit) { - if (isset($output[$cat][$suit])) { - print $output[$cat][$suit]; - } - print "\t"; + foreach ($categories as $cat) { + if (!$raw) { + if (isset(self::$catHeaders[$cat])) { + print self::$catHeaders[$cat]; + } + print "\t"; + } + foreach ($suits as $suit) { + if (isset($output[$cat][$suit])) { + print $output[$cat][$suit]; + } + print "\t"; + } + print "\n"; } - print "\n"; - } - } + } -} + } require_once('lib/OsikaEvaluator.php'); @@ -102,81 +101,81 @@ $hand = str_replace(',', '|', array_pop($argv)); $options = getopt('hf:c:s:', array('help', 'format:', 'categories:', 'suits:')); if (isset($options['h']) || isset($options['help']) || $argc < 2) { - Osika::printHelp(); - exit; + Osika::printHelp(); + exit; } $format = isset($options['f']) ? $options['f'] : (isset($options['format']) ? $options['format'] : 'table'); if (is_array($format)) { - $format = array_pop($format); + $format = array_pop($format); } $catOptions = array(); if (isset($options['c'])) { - $catOptions = array_merge($catOptions, (array)$options['c']); + $catOptions = array_merge($catOptions, (array)$options['c']); } if (isset($options['categories'])) { - $catOptions = array_merge($catOptions, (array)$options['categories']); + $catOptions = array_merge($catOptions, (array)$options['categories']); } $categories = array(); foreach ($catOptions as $cat) { - $categories = array_merge($categories, explode(',', $cat)); + $categories = array_merge($categories, explode(',', $cat)); } if (empty($categories)) { - $categories = array('all'); + $categories = array('all'); } if (in_array('all', $categories)) { - $categories = array('lh','lh_plus','lh_10','lh_short','lh_subtotal','lu','subtotal','lsz','lu_plus','short_suit','major_suit','l10n','total'); + $categories = array('lh','lh_plus','lh_10','lh_short','lh_subtotal','lu','subtotal','lsz','lu_plus','short_suit','major_suit','l10n','total'); } $suitOptions = array(); if (isset($options['s'])) { - $suitOptions = array_merge($suitOptions, (array)$options['s']); + $suitOptions = array_merge($suitOptions, (array)$options['s']); } if (isset($options['suits'])) { - $suitOptions = array_merge($suitOptions, (array)$options['suits']); + $suitOptions = array_merge($suitOptions, (array)$options['suits']); } $suits = array(); foreach ($suitOptions as $suit) { - $suits = array_merge($suits, explode(',', $suit)); + $suits = array_merge($suits, explode(',', $suit)); } if (empty($suits)) { - $suits = array('all'); + $suits = array('all'); } if (in_array('all', $suits)) { - $suits = array('s','h','d','c','total'); + $suits = array('s','h','d','c','total'); } try { - $eval = new OsikaEvaluator($hand); - $result = $eval->evaluate(); - $output = array(); - foreach ($result as $categoryName => $category) { - if (in_array($categoryName, $categories)) { - $outCat = array(); - foreach ($category as $suitName => $suit) { - if (in_array($suitName, $suits)) { - $outCat[$suitName] = $suit; - } + $eval = new OsikaEvaluator($hand); + $result = $eval->evaluate(); + $output = array(); + foreach ($result as $categoryName => $category) { + if (in_array($categoryName, $categories)) { + $outCat = array(); + foreach ($category as $suitName => $suit) { + if (in_array($suitName, $suits)) { + $outCat[$suitName] = $suit; + } + } + $output[$categoryName] = $outCat; } - $output[$categoryName] = $outCat; - } - } - switch ($format) { - case 'json': - print json_encode($output)."\n"; - exit; - case 'raw': - Osika::printTable($output, $categories, $suits, TRUE); - exit; - case 'table': - default: - Osika::printTable($output, $categories, $suits); - exit; - } + } + switch ($format) { + case 'json': + print json_encode($output)."\n"; + exit; + case 'raw': + Osika::printTable($output, $categories, $suits, TRUE); + exit; + case 'table': + default: + Osika::printTable($output, $categories, $suits); + exit; + } } catch (Exception $e) { - print 'ERROR: '.$e->getMessage()."\n"; + print 'ERROR: '.$e->getMessage()."\n"; } ?> |