1 <?php 2 /* 3 * 黑桃 @ 4 * 红桃 # 5 * 片花 % 6 * 梅花 * 7 * */ 8 9 //fwrite(STDOUT,'name ?'.PHP_EOL); 10 //fscanf(STDIN,"%s",$name); 11 12 /* 13 * 可配置参数: 14 * 一副牌54张 15 * 一局n副牌 16 * 一局m个人 17 * 一局分成x组 18 * 19 * 0.是否开始 20 * 1.初始化数据54张牌,抽出3张底牌,3个人,分成2组,A组1人,B组2人 21 * 2.51张牌,发牌给3个人,先发给A组 22 * 3.随机一人开始出牌 23 * 4.接下来一人出牌 24 * 5.一人手中无牌,该组胜利 25 * 6.计算输赢,一张牌1分,把得分平均发给赢组的人员 26 * */ 27 28 class game 29 { 30 private static $playCards = [ 31 2,2,2,2, 32 3,3,3,3, 33 4,4,4,4, 34 5,5,5,5, 35 6,6,6,6, 36 7,7,7,7, 37 8,8,8,8, 38 9,9,9,9, 39 10,10,10,10, 40 11,11,11,11, //J 41 12,12,12,12, //Q 42 13,13,13,13, //K 43 14,14,14,14, //A 44 20, //小王 45 21 //大王 46 ]; 47 public $playCardsNum; 48 public $peopleNum; 49 public $termNum; 50 public $people = array(); 51 private $landlord=null; //当前地主id做个标记 52 private $prevPerson=null; //上个出牌人的id 53 private $currPerson=null; //当前出牌人id 54 private $prevCard; //上个人出的牌 55 private $prevCardType; //上个人出牌型 56 private $cardTpyeObj; 57 58 public static $input=null; 59 public static $start; 60 61 62 public function __construct($playCardsNum=1, $peopleNum=3, $termNum=2) 63 { 64 $this->playCardsNum = $playCardsNum; 65 $this->peopleNum = $peopleNum; 66 $this->termNum = $termNum; 67 $this->cardTpyeObj = CardTpye::obj(); 68 69 self::start() && $this->run(); 70 } 71 72 public function run() 73 { 74 $this->peopleInit(); 75 76 while(self::$start) 77 { 78 //发牌 79 $this->cardInit(); 80 //争地主 81 $this->landlord(); 82 $this->showPerson(); 83 //出牌 84 $this->playHand(); 85 //清空每局的垃圾信息 86 $this->clean(); 87 //重新开始 88 self::start(); 89 } 90 91 self::notice("bye ~"); 92 } 93 94 95 96 //询问是否开始 97 public static function start() 98 { 99 self::notice("start or close ?"); 100 self::notice("start:1 close:0"); 101 self::getInput(); 102 if(self::$input == 0) 103 { 104 self::$start = false; 105 self::delInput(); 106 return false; 107 }else{ 108 self::$start = true; 109 self::delInput(); 110 return true; 111 } 112 } 113 114 //初始化人员 115 public function peopleInit() 116 { 117 //初始化人员 118 for($peoson=0; $peoson<$this->peopleNum; $peoson++) 119 { 120 self::notice($peoson." name ?"); 121 self::getInput(); 122 $peosonInfo = array( 123 "name" => self::$input, 124 "win" => 0, 125 "status" => 0, //0农民 1地主 126 "cards" => array() 127 ); 128 if(empty(self::$input)) 129 { 130 $peoson--; 131 }else { 132 array_push($this->people, $peosonInfo); 133 } 134 self::delInput(); 135 } 136 } 137 138 //开始发牌 139 public function cardInit() 140 { 141 shuffle(self::$playCards); 142 foreach(self::$playCards as $key=>$card) 143 { 144 $tmpNum = $key % $this->peopleNum; 145 array_push($this->people[$tmpNum]['cards'], $card); 146 } 147 148 array_walk($this->people,function(&$peoson){ 149 sort($peoson['cards']); 150 }); 151 } 152 153 //显示每个人的牌 154 public function showPerson($id=null) 155 { 156 $status = array("peasant","landlord"); 157 158 if($id === null){ 159 array_walk($this->people,function(&$peoson) use($status){ 160 $notice = $status[$peoson['status']]." ".$peoson['name'].": ".implode(',',$peoson['cards']); 161 self::notice($notice); 162 }); 163 }else{ 164 $notice = $status[$this->people[$id]['status']]." ".$this->people[$id]['name'].": ".implode(',',$this->people[$id]['cards']); 165 self::notice($notice); 166 } 167 } 168 169 //争地主 170 public function landlord() 171 { 172 $id = 0; 173 $score = 0; 174 foreach($this->people as $key=>$peoson) 175 { 176 self::notice($key." ".$peoson['name']." ".": please input score [1,2,3]"); 177 self::getInput(); 178 if(self::$input>$score) { 179 $score=self::$input; 180 $id=$key; 181 } 182 self::notice("s:".$score." id:".$id); 183 } 184 $this->people[$id]['status'] = 1; 185 $this->landlord = $id; 186 self::delInput(); 187 } 188 189 //出牌 190 public function playHand() 191 { 192 $play = true; 193 while($play) 194 { 195 //计算该谁出牌了 196 if(is_null($this->currPerson)){ 197 $this->currPerson = $this->landlord; 198 }else{ 199 $needPlay = $this->currPerson + 1; 200 $this->currPerson = !isset($this->people[$needPlay]) ? 0:$needPlay; 201 } 202 203 204 //没通过就重出 205 do { 206 self::notice(PHP_EOL . PHP_EOL . "please play"); 207 $this->showPerson($this->currPerson); 208 self::getInput(); 209 //验证出牌规则 210 $pass = $this->ruleCheck(); 211 !$pass && self::notice("error."); 212 }while(!$pass); 213 214 //把出的牌删除 215 if(!empty(self::$input)) 216 { 217 self::notice("play: " . self::$input); 218 $playCards = explode(',', self::$input); 219 foreach ($playCards as $card) { 220 $key = array_search($card, $this->people[$this->currPerson]['cards']); 221 unset($this->people[$this->currPerson]['cards'][$key]); 222 } 223 224 //记录下出的牌和个人id 225 $this->prevPerson = $this->currPerson; 226 $this->prevCard = self::$input; 227 self::log("p:".$this->prevPerson." c:".$this->prevCard); 228 } 229 230 //赢了 231 if(empty($this->people[$this->currPerson]['cards'])) 232 { 233 $this->people[$this->currPerson]['win'] ++ ; 234 self::notice($this->people[$this->currPerson]['name']." win"); 235 $play = false; 236 } 237 238 self::delInput(); 239 } 240 241 self::notice("game over"); 242 } 243 244 //验证规则 245 public function ruleCheck() 246 { 247 248 /* 249 * 牌型验证,和上局人出的牌型一致 250 * 0.单张 一张牌一样 251 * 1.两对 两张牌一样 252 * 2.三对 三张牌一样 253 * 3.三队带一 254 * 4.三队带二对 255 * 5.四张炸 256 * 6.炸带单张 257 * 6.炸带两队 258 * 7.单顺最小5张 连续的牌,差为1 259 * 8.两对顺 最小三对 260 * 9.三队顺 最小2对 261 * 10.三队顺带2个单牌 262 * 11.三队顺带2个两对 263 * 12.四炸顺 264 * 13.四炸顺带两个单牌 265 * 14.四炸顺带两个对 266 * */ 267 268 //如果出空 269 if(is_null(self::$input)) 270 { 271 //第一次不能出空 272 if(empty($this->prevCard)){ 273 return false; 274 } 275 //转一圈到自己了,不能出空 276 if($this->currPerson == $this->prevPerson){ 277 return false; 278 } 279 280 return true; 281 } 282 283 284 $cards = explode(',',self::$input); 285 $type = $this->cardTpyeObj->getType($cards); 286 //第一次出,或其他人都不要,转一圈到自己了 287 if(is_null($this->prevPerson) || $this->currPerson==$this->prevPerson) 288 { 289 if($type==0){ 290 return false; 291 }else{ 292 $this->prevCardType = $type; 293 return true; 294 } 295 }else{ 296 //根据类型验证大小 297 if($type==0 || $type!=$this->prevCardType){ 298 return false; 299 }else{ 300 $prevCards = explode(",",$this->prevCard); 301 $big = $this->cardTpyeObj->size($type, $prevCards, $cards); 302 return $big; 303 } 304 } 305 306 307 } 308 309 //清空每局的垃圾信息 310 public function clean() 311 { 312 array_walk($this->people,function(&$person){ 313 $person['staus'] = 0; 314 $person['cards'] = array(); 315 }); 316 $this->landlord = null; 317 $this->prevPerson = null; 318 $this->prevCard = ""; 319 } 320 321 322 323 public static function notice($message) 324 { 325 fwrite(STDOUT,$message.PHP_EOL); 326 } 327 public static function getInput() 328 { 329 fscanf(STDIN,'%s',self::$input); 330 } 331 public static function delInput() 332 { 333 self::$input = null; 334 } 335 public static function log($message) 336 { 337 $str = time()." ".$message." "; 338 file_put_contents("log.txt", $str, FILE_APPEND); 339 } 340 341 } 342 343 $game = new game(); 344 345 346 347 class CardTpye 348 { 349 private static $obj; 350 351 private function __construct(){} 352 private function __clone(){} 353 public static function obj() 354 { 355 if(!isset(self::$obj)) 356 { 357 self::$obj = new self; 358 } 359 return self::$obj; 360 } 361 362 //类型验证 363 public function getType(array $cards) 364 { 365 $type = 0; 366 switch(count($cards)){ 367 case 1: 368 $type=1;break; 369 case 2: 370 $this->dui_2($cards) && $type=2; 371 break; 372 case 3: 373 $this->dui_3($cards) && $type=3; 374 break; 375 case 4: 376 $this->dui_3_1($cards) && $type=4; 377 $this->bomb_4($cards) && $type=5; 378 break; 379 case 5: 380 $this->dui_3_2($cards) && $type=6; 381 $this->bomb_4_1($cards) && $type=7; 382 break; 383 default: 384 $type=0; 385 } 386 387 return $type; 388 } 389 //大小验证 390 public function size($type, array $prev, array $current) 391 { 392 $big = false; 393 switch($type){ 394 case 1: 395 $big = $this->one_size($prev, $current); 396 break; 397 case 2: 398 $big = $this->dui_2_size($prev, $current); 399 break; 400 case 3: 401 $big = $this->dui_3_size($prev, $current); 402 break; 403 case 4: 404 $big = $this->dui_3_1_size($prev, $current); 405 break; 406 case 5: 407 $big = $this->bomb_4_size($prev, $current); 408 break; 409 case 6: 410 $big = $this->dui_3_2_size($prev, $current); 411 break; 412 case 7: 413 $big = $this->bomb_4_1_size($prev, $current); 414 break; 415 default: 416 break; 417 } 418 419 return $big; 420 } 421 422 423 424 /********************验证大小***************************/ 425 private function one_size(array $prev, array $current) 426 { 427 return self::bigOrSmall($prev[0],$current[0]); 428 } 429 430 private function dui_2_size(array $prev, array $current) 431 { 432 return self::bigOrSmall($prev[0],$current[0]); 433 } 434 435 private function dui_3_size(array $prev, array $current) 436 { 437 return self::bigOrSmall($prev[0],$current[0]); 438 } 439 440 private function dui_3_1_size(array $prev, array $current) 441 { 442 //获取三张 443 $getDui_3 = function (array $cards){ 444 if($cards[0] == $cards[1]){ 445 return array_slice($cards,0,3); 446 }else{ 447 return array_slice($cards,1,3); 448 } 449 }; 450 451 $prevDui_3 = $getDui_3($prev); 452 $currDui_3 = $getDui_3($current); 453 return self::bigOrSmall($prevDui_3[0], $currDui_3[0]); 454 } 455 456 private function bomb_4_size(array $prev, array $current) 457 { 458 return self::bigOrSmall($prev[0], $current[0]); 459 } 460 461 private function dui_3_2_size(array $prev, array $current) 462 { 463 $getDui_3 = function (array $cards) 464 { 465 sort($cards); 466 if($cards[0]==$cards[1] && $cards[1]==$cards[2]) 467 { 468 return array_slice($cards, 0, 3); 469 }else{ 470 return array_slice($cards, 2, 3); 471 } 472 }; 473 $prevDui_3 = $getDui_3($prev); 474 $currDui_3 = $getDui_3($current); 475 return self::bigOrSmall($prevDui_3[0], $currDui_3[0]); 476 } 477 478 private function bomb_4_1_size(array $prev, array $current) 479 { 480 $getDui_4 = function (array $cards) 481 { 482 sort($cards); 483 if($cards[0] == $cards[1]) 484 { 485 return array_slice($cards, 0, 4); 486 }else{ 487 return array_slice($cards, 1, 4); 488 } 489 }; 490 491 $prevDui_4 = $getDui_4($prev); 492 $currDui_4 = $getDui_4($current); 493 return self::bigOrSmall($prevDui_4[0], $currDui_4[0]); 494 } 495 496 497 498 private static function bigOrSmall($pre, $cur) 499 { 500 if($cur <= $pre) 501 { 502 return false; 503 }else{ 504 return true; 505 } 506 } 507 508 /*****************验证牌型*************************/ 509 /* 510 * type=2 511 * 两张牌---对子验证 512 * 规则:两张牌型一样 513 * */ 514 private function dui_2(array $input) 515 { 516 if($input[0] == $input[1]) 517 { 518 return true; 519 }else{ 520 return false; 521 } 522 } 523 524 /* 525 * type=3 526 * 三张牌---三对验证 527 * 规则:三张牌一样 528 * */ 529 private function dui_3(array $input) 530 { 531 if($input[0]==$input[1] && $input[1]==$input[2]) 532 { 533 return true; 534 }else{ 535 return false; 536 } 537 } 538 539 /* 540 * type=4 541 * 四张牌---三带一 542 * 规则:前三张一样,第四张随便 543 * */ 544 private function dui_3_1(array $input) 545 { 546 //前三张一样 547 if($input[0]==$input[1]) 548 { 549 if($input[1]==$input[2]) 550 { 551 return true; 552 }else{ 553 return false; 554 } 555 }else{ 556 if($input[1]==$input[2] && $input[2]==$input[3]) 557 { 558 return true; 559 }else{ 560 return false; 561 } 562 } 563 } 564 565 566 /* 567 * type=5 568 * 四张牌---炸弹 569 * 规则:四张一样 570 * */ 571 private function bomb_4(array $input) 572 { 573 if($input[0]==$input[1] && $input[1]==$input[2] && $input[2]==$input[3]) 574 { 575 return true; 576 }else{ 577 return false; 578 } 579 } 580 581 /* 582 * type=6 583 * 五张牌---三带二 584 * 规则:前三张一样,后两张一样 585 * */ 586 private function dui_3_2(array $input) 587 { 588 sort($input); 589 if($input[0]==$input[1] && $input[1]==$input[2]) 590 { 591 $dui_3 = array_slice($input, 0, 3); 592 $dui_2 = array_slice($input, 3, 2); 593 }else{ 594 $dui_2 = array_slice($input, 0, 2); 595 $dui_3 = array_slice($input, 2, 3); 596 } 597 598 if($this->dui_3($dui_3) && $this->dui_2($dui_2)) 599 { 600 return true; 601 }else{ 602 return false; 603 } 604 605 } 606 607 /* 608 * type=7 609 * 五张牌---四带一 610 * 规则:四张一样的,一张单个 611 * */ 612 private function bomb_4_1(array $input) 613 { 614 if($input[0] == $input[1]) 615 { 616 if($input[1]==$input[2] && $input[2]==$input[3]){ 617 return true; 618 }else{ 619 return false; 620 } 621 }else{ 622 if($input[1]==$input[2] && $input[2]==$input[3] && $input[3]==$input[4]) 623 { 624 return true; 625 }else{ 626 return false; 627 } 628 } 629 } 630 631 632 633 }