'player', 'poker' => $poker, 'num' => $num, 'color' => $color, 'block_num' => ($blockNum - 1), 'block_id' => $blockId, ]; Eos::pubEvent('baccarat:new_poker', $eventData); // 庄 list($num, $color, $blockId) = self::blockNum2Poker($blockNum++, $objRedis); $poker = self::toPoker($num, $color); $banker[] = $poker; $bankerNum[] = $num; $blockInfo['banker'][] = compact('blockId', 'poker'); $eventData = [ 'type' => 'banker', 'poker' => $poker, 'num' => $num, 'color' => $color, 'block_num' => ($blockNum - 1), 'block_id' => $blockId, ]; Eos::pubEvent('baccarat:new_poker', $eventData); // 闲 list($num, $color, $blockId) = self::blockNum2Poker($blockNum++, $objRedis); $poker = self::toPoker($num, $color); $player[] = $poker; $playerNum[] = $num; $blockInfo['player'][] = compact('blockId', 'poker'); $eventData = [ 'type' => 'player', 'poker' => $poker, 'num' => $num, 'color' => $color, 'block_num' => ($blockNum - 1), 'block_id' => $blockId, ]; Eos::pubEvent('baccarat:new_poker', $eventData); // 庄 list($num, $color, $blockId) = self::blockNum2Poker($blockNum++, $objRedis); $poker = self::toPoker($num, $color); $banker[] = $poker; $bankerNum[] = $num; $blockInfo['banker'][] = compact('blockId', 'poker'); $eventData = [ 'type' => 'banker', 'poker' => $poker, 'num' => $num, 'color' => $color, 'block_num' => ($blockNum - 1), 'block_id' => $blockId, ]; Eos::pubEvent('baccarat:new_poker', $eventData); // 算对子 $playerPair = self::isPair($playerNum); // 闲对 $bankerPair = self::isPair($bankerNum); // 庄对 // 算点数 $playerPoint = self::pokerPoint($playerNum); $playerPointSource = $playerPoint; $bankerPoint = self::pokerPoint($bankerNum); // 闲判断加牌 $playerExtNum = 0; if ($playerPoint < 6 && $bankerPoint < 8) { list($playerExtNum, $color, $blockId) = self::blockNum2Poker($blockNum++, $objRedis); $poker = self::toPoker($playerExtNum, $color); $player[] = $poker; $playerNum[] = $playerExtNum; $blockInfo['player'][] = compact('blockId', 'poker'); $playerPoint = self::pokerPoint($playerNum); $eventData = [ 'type' => 'player', 'poker' => $poker, 'num' => $playerExtNum, 'color' => $color, 'block_num' => ($blockNum - 1), 'block_id' => $blockId, ]; Eos::pubEvent('baccarat:new_poker', $eventData); } // 庄判断加牌 if (self::addPokerBanker($playerPointSource, $bankerPoint, $playerExtNum)) { list($num, $color, $blockId) = self::blockNum2Poker($blockNum, $objRedis); $poker = self::toPoker($num, $color); $banker[] = $poker; $bankerNum[] = $num; $blockInfo['banker'][] = compact('blockId', 'poker'); $bankerPoint = self::pokerPoint($bankerNum); $eventData = [ 'type' => 'banker', 'poker' => $poker, 'num' => $num, 'color' => $color, 'block_num' => $blockNum, 'block_id' => $blockId, ]; Eos::pubEvent('baccarat:new_poker', $eventData); } if ($bankerPoint > $playerPoint) { $win = self::WIN_BANKER; // 庄赢 } elseif ($playerPoint > $bankerPoint) { $win = self::WIN_PLAYER; // 闲赢 } else { $win = self::WIN_TIE; } $revealInfo = compact('win', 'player', 'banker', 'playerPair', 'bankerPair', 'playerNum', 'bankerNum', 'playerPoint', 'bankerPoint', 'revealBlockNum', 'blockInfo'); return [$win, $player, $banker, $playerPair, $bankerPair, $revealBlockNum, $revealInfo]; } /** * 判断庄是否需要加牌 * @param $playerPoint * @param $bankerPoint * @param $playerExtNum * @wiki https://zh.wikipedia.org/wiki/百家樂#博牌規則 * @return bool */ private static function addPokerBanker($playerPoint, $bankerPoint, $playerExtNum) { $playerExtNum > 9 && $playerExtNum = 0; $add = false; if ($playerPoint >= 8) { return false; } if ($bankerPoint < 3) { $add = true; } elseif ($bankerPoint == 3 && $playerExtNum != 8) { $add = true; } elseif ($bankerPoint == 4 && !in_array($playerExtNum, [0, 1, 8, 9])) { $add = true; } elseif ($bankerPoint == 5 && !in_array($playerExtNum, [0, 1, 2, 3, 8, 9])) { $add = true; } elseif ($bankerPoint == 6 && $playerPoint > 0 && $playerPoint < 6 && in_array($playerExtNum, [6, 7])) { $add = true; } return $add; } /** * 算点数 * @param array $pokerNums * @return int */ private static function pokerPoint(array $pokerNums) { $total = 0; // 10,J,Q,K 当 0 处理 foreach ($pokerNums as $num) { $num > 9 && $num = 0; $total += $num; } return $total % 10; // 超过10取各位 } /** * 对子 * @param array $nums * @return bool */ private static function isPair(array $nums) { return count(array_unique($nums)) === 1; } /** * @param $blockNum * @param null $objRedis * @return array * @throws Exception */ private static function blockNum2Poker($blockNum, $objRedis = null) { $blockId = self::getBlockIdWithCache($blockNum, $objRedis); if (!$blockId) { throw new Exception("num:{$blockNum}, 获取blockId失败"); } list($num, $color) = self::code2Poker($blockId); return [$num, $color, $blockId]; } public static function code2Poker($code) { $code2 = preg_replace('/[^0-9a-d]/i', '', $code); $len = strlen($code2); // 取num $num = 0; $i = $len - 1; for (; $i > 0; $i--) { $c = $code2[$i]; $num = hexdec($c); if ($num > 0) { break; } } // 取花色 $color = 0; $i--; for (; $i > 0; $i--) { $c = $code2[$i]; $color = hexdec($c); if ($color >= 0 && $color <= 3) { break; } } return [$num, $color]; } /** * 牌序号值 * @param $num * @param $color * @return int */ public static function toPoker($num, $color) { if ($num < 1 || $num > 13) { return 0; } if ($color < 0 || $color > 3) { return 0; } return intval($color*13 + $num); } /** * 牌面值 * @param $poker * @return int */ public static function toPokerNum($poker) { return (($poker - 1) % 13) + 1; } /** * 牌花色 * @param $poker * @return int */ public static function toPockColor($poker) { return intval(($poker - 1) / 13); } private static function getBlockIdWithCache($blockNum, $objRedis = null) { !$objRedis && $objRedis = dwRedis::init(Eos::REDIS_SERV); $key = self::REDIS_PRE_BLOCK_ID . $blockNum; $blockId = $objRedis->get($key); if (!$blockId) { $blockId = Eos::getBlockId($blockNum); if ($blockId) { $objRedis->setex($key, 300, $blockId); } } return $blockId; } /** * 近N期开奖信息 * @param int $limit * @return array */ public function winData($limit = 50) { $list = $this->objTable->getAll(['game_state' => self::STATUS_FINISH], [ '_field' => 'id, winner, banker_pair, player_pair, reveal_trx_id, reveal_block_num, reveal_info', '_sortKey' => 'id DESC', '_limit' => $limit, ]); foreach ($list as $k => $v) { $v['id'] = intval($v['id']); $v['winner'] = intval($v['winner']); $v['banker_pair'] = intval($v['banker_pair']); $v['player_pair'] = intval($v['player_pair']); $v['reveal_block_num'] = intval($v['reveal_block_num']); $revealInfo = json_decode($v['reveal_info'], true); unset($v['reveal_info']); $v['block_info'] = $revealInfo['blockInfo']; $list[$k] = $v; } return $list ?: []; } /** * 游戏信息 * @param $old * @param $new * @param $player * @return array */ public function info($old, $new, $player) { $data = []; $keyword = [ '_field' => 'id, ttl, game_state, create_time, update_time_int, reveal_info', ]; $games = $this->objTable->getAll(['id' => [$old, $new]], $keyword); $games = arrayFormatKey($games, 'id'); $data['old'] = $games[$old] ?: []; $data['old']['reveal_info'] = json_decode($data['old']['reveal_info'], true); $data['new'] = $games[$new] ?: []; unset($data['new']['reveal_info']); $data['new']['timeout'] = max(strtotime($data['new']['create_time']) + $data['new']['ttl'] - time(), 0); $row = null; if ($player) { $objOffer = new Offer(); $row = $objOffer->objTable->getRow(['game_id' => $old, 'player' => $player, 'state' => self::STATUS_FINISH], [ '_field' => 'sum(offerall_int) offerall, sum(win_int) win', ]); } $data['old']['offer'] = $row ?: null; return $data; } /** * 在线玩家队列 * @author solu * @param $player */ public static function setPlayerOnline($player) { $objRedis = dwRedis::init(Eos::REDIS_SERV); $time = time(); $objRedis->zAdd(self::REDIS_PLAYER_ONLINE_SET, $time, $player); $len = $objRedis->zCard(self::REDIS_PLAYER_ONLINE_SET); if ($len > self::MAX_PLAYER_ONLINE_COUNT) { $out = $len - self::MAX_PLAYER_ONLINE_COUNT; $objRedis->zRemRangeByRank(self::REDIS_PLAYER_ONLINE_SET, 0, $out-1); } } /** * 在线信息 * @author solu * @param $limit * @return array */ public static function getOnlineInfo($limit = 10) { $objRedis = dwRedis::init(Eos::REDIS_SERV); self::trimOnline(); $total = $objRedis->zCard(self::REDIS_PLAYER_ONLINE_SET); $list = $objRedis->zRevRange(self::REDIS_PLAYER_ONLINE_SET, 0, $limit); return [$total, $list]; } /** * 整理在线玩家 * @author solu */ public static function trimOnline() { $objRedis = dwRedis::init(Eos::REDIS_SERV); $timeout = time() - self::PLAYER_TIME_OUT; return $objRedis->zRemRangeByScore(self::REDIS_PLAYER_ONLINE_SET, '-inf', $timeout); } /** * 游戏信息 * @author solu * @param array $gameIds * @return array */ public function getGameRevealInfo(array $gameIds) { $items = $this->objTable->getAll(['id' => $gameIds], ['_field' => 'id, game_state, reveal_info']); $data = []; foreach ($items as $v) { $id = $v['id']; $v['reveal_info'] = $v['reveal_info'] ? json_decode($v['reveal_info'], true) : null; $data[$id] = $v; } return $data; } }