本文章使用php编写三公的算牌逻辑,不引用外面的库,全部手写,拿来即用。
如有疑问可以联系我。
<?php
class POKER_NUM
{
const POKER_NUM_A = 1; // A
const POKER_NUM_2 = 2; // 2
const POKER_NUM_3 = 3; // 3
const POKER_NUM_4 = 4; // 4
const POKER_NUM_5 = 5; // 5
const POKER_NUM_6 = 6; // 6
const POKER_NUM_7 = 7; // 7
const POKER_NUM_8 = 8; // 8
const POKER_NUM_9 = 9; // 9
const POKER_NUM_T = 10; // 10
const POKER_NUM_J = 11; // J
const POKER_NUM_Q = 12; // Q
const POKER_NUM_K = 13; // K
}
class POKER_TYPE
{
const POKER_TYPE_BLACK = 4; // 黑桃
const POKER_TYPE_RED = 3; // 红桃
const POKER_TYPE_CLUB = 2; // 梅花
const POKER_TYPE_DIAMOND = 1; // 方片
}
class POKER_RESULT
{
const SG_INVALID = -1; // 非法牌型
const SG_POINT_0 = 0; // 0点
const SG_POINT_1 = 100; // 1点
const SG_POINT_2 = 200; // 2点
const SG_POINT_3 = 300; // 3点
const SG_POINT_4 = 400; // 4点
const SG_POINT_5 = 500; // 5点
const SG_POINT_6 = 600; // 6点
const SG_POINT_7 = 700; // 7点
const SG_POINT_8 = 800; // 8点
const SG_POINT_9 = 900; // 9点
const SG_THREE_MAN = 1000; // 三公
const SG_BOMB = 1100; // 炸弹 KKK(1113) > QQQ > JJJ > TTT > 999 > 888 > 777 > 666 > 555 > 444 > 222 > AAA(1101)
const SG_BAOJIU = 1333; // 爆玖 (333)
}
const POKER_RESULT_TIMES = [
POKER_RESULT::SG_INVALID => 0,
POKER_RESULT::SG_POINT_0 => 1,
POKER_RESULT::SG_POINT_1 => 1,
POKER_RESULT::SG_POINT_2 => 1,
POKER_RESULT::SG_POINT_3 => 1,
POKER_RESULT::SG_POINT_4 => 1,
POKER_RESULT::SG_POINT_5 => 1,
POKER_RESULT::SG_POINT_6 => 1,
POKER_RESULT::SG_POINT_7 => 2,
POKER_RESULT::SG_POINT_8 => 2,
POKER_RESULT::SG_POINT_9 => 2,
POKER_RESULT::SG_THREE_MAN => 3,
POKER_RESULT::SG_BOMB => 4,
POKER_RESULT::SG_BAOJIU => 5
];
class Poker_Style_t
{
public $num; // 牌
public $type; // 花色
public function __construct($num, $type)
{
$this->num = $num;
$this->type = $type;
}
}
const SGTags = [
POKER_RESULT::SG_INVALID => '非法牌',
POKER_RESULT::SG_POINT_0 => '0点',
POKER_RESULT::SG_POINT_1 => '1点',
POKER_RESULT::SG_POINT_2 => '2点',
POKER_RESULT::SG_POINT_3 => '3点',
POKER_RESULT::SG_POINT_4 => '4点',
POKER_RESULT::SG_POINT_5 => '5点',
POKER_RESULT::SG_POINT_6 => '6点',
POKER_RESULT::SG_POINT_7 => '7点',
POKER_RESULT::SG_POINT_8 => '8点',
POKER_RESULT::SG_POINT_9 => '9点',
POKER_RESULT::SG_THREE_MAN => '三公',
POKER_RESULT::SG_BOMB => '炸弹',
POKER_RESULT::SG_BAOJIU => '爆玖'
];
class PokerResult
{
public $cards; // 牌
public $rank; // 评分
public $style; // 牌型
public $message;// 牌型的文字描述
public function __construct($style, $rank = -1, $message = '非法牌')
{
$this->rank = $rank;
$this->style = $style;
$this->message = $message;
}
}
class Hand
{
private $pokers = []; // 牌型 [{num, type}]
private $result; // 结果
public function __construct(Array $pokers)
{
$this->pokers = $pokers;
$this->calcPoint();
$this->calcRank();
$this->result->cards = $pokers;
}
/**
* 算点数
*/
public
function calcPoint()
{
// 过滤非法牌型, 比如排的数目不是五张,牌的花色有问题等等. todo
if (count($this->pokers) != 3) {
$this->result = new PokerResult(POKER_RESULT::SG_INVALID);
return;
}
// 判断是否有重复的牌
$arr = [];
for ($i = 0; $i < count($this->pokers); $i++) {
$index = $this->pokers[$i]->num * 100 + $this->pokers[$i]->type;
if (isset($arr[$index]) && $arr[$index] == 1) {
$this->result = new PokerResult(POKER_RESULT::SG_INVALID);
return;
}
$arr[$index] = 1;
}
// 是不是爆玖
if ($this->pokers[0]->num == POKER_NUM::POKER_NUM_3 &&
$this->pokers[1]->num == POKER_NUM::POKER_NUM_3 &&
$this->pokers[2]->num == POKER_NUM::POKER_NUM_3) {
$this->result = new PokerResult(POKER_RESULT::SG_BAOJIU);
} else if ($this->pokers[0]->num == $this->pokers[1]->num &&
$this->pokers[1]->num == $this->pokers[2]->num &&
$this->pokers[0]->num != POKER_NUM::POKER_NUM_3) { // 是不是炸弹
$this->result = new PokerResult(POKER_RESULT::SG_BOMB);
} else if ($this->pokers[0]->num >= POKER_NUM::POKER_NUM_J &&
$this->pokers[1]->num >= POKER_NUM::POKER_NUM_J &&
$this->pokers[2]->num >= POKER_NUM::POKER_NUM_J) { // 是不是三公
$this->result = new PokerResult(POKER_RESULT::SG_THREE_MAN);
} else { // 点数牌
$a0 = $this->pokers[0]->num > POKER_NUM::POKER_NUM_T ? POKER_NUM::POKER_NUM_T : $this->pokers[0]->num;
$a1 = $this->pokers[1]->num > POKER_NUM::POKER_NUM_T ? POKER_NUM::POKER_NUM_T : $this->pokers[1]->num;
$a2 = $this->pokers[2]->num > POKER_NUM::POKER_NUM_T ? POKER_NUM::POKER_NUM_T : $this->pokers[2]->num;
$point = ($a0 + $a1 + $a2) % 10;
$this->result = new PokerResult($point * 100); // 点数 * 100 = 牌型
}
return;
}
/**
* 算分
*/
public
function calcRank()
{
$maxPoker = $this->_getMaxPokerNum();
// 计算公仔牌的数量
$threeManNum = 0;
for ($i = 0; $i < 3; $i++) {
if ($this->pokers[$i]->num > POKER_NUM::POKER_NUM_T) {
$threeManNum++;
}
}
// 针对不同牌型计算rank
if ($this->result->style == POKER_RESULT::SG_BAOJIU) {
// 爆玖 rank = 1333 写死 !!!
$this->result->rank = POKER_RESULT::SG_BAOJIU;
} else if ($this->result->style == POKER_RESULT::SG_BOMB) {
// 炸弹 rank = 炸弹底分 + 牌面值
$this->result->rank = $this->result->style + $maxPoker['num']; // + number_format($maxPoker['type'] / 10, 1);
} else if ($this->result->style == POKER_RESULT::SG_THREE_MAN) {
// 三公 rank = 三公底分 + 最大牌面值 + 最大牌花色
$this->result->rank = $this->result->style + $maxPoker['num'] + number_format($maxPoker['type'] / 10, 1);
} else {
// 点数 rank = 点数底分 + 三公数量 * 30 + 最大牌面值 + 最大牌花色
$this->result->rank = $this->result->style + 30 * $threeManNum +
$maxPoker['num'] + number_format($maxPoker['type'] / 10, 1);
}
$this->result->message = SGTags[$this->result->style];
}
public
function getResult()
{
return $this->result;
}
/**
* 获取最大牌面大小
*/
private
function _getMaxPokerNum()
{
$num = $this->pokers[0]->num;
$type = $this->pokers[0]->type;
for ($i = 1; $i < count($this->pokers); $i++) {
if ($this->pokers[$i]->num > $num ||
($this->pokers[$i]->num == $num && $this->pokers[$i]->type > $type)) {
$num = $this->pokers[$i]->num;
$type = $this->pokers[$i]->type;
}
}
return ['num' => $num, 'type' => $type];
}
}