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."\r\n";
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 }