Jump to content

Criar um motor de Poker em php


Recommended Posts

Posted

Estou a desenvolver um jogo de poker, mais precisamente Poker Texas Hold'n, mas estou com dificuldades na parte principal do código, que é fazer a correspondência das mãos que saiem e definir assim qual a mão vencedora.

Actualmente o código abaixo apresentado, já cria um baralho de cartas, com os ternos/cartas, e já faz a randomização das cartas, agora falta a parte lógica, como detectar as mãos e atribuir-lhes os valores..

poker.php

<?php header('Content-Type: text/html; charset=utf-8');
/*
ID's das cartas


Ternos:
-> Ouros = O
-> Paus = P
-> Corações = C
-> Espadas = E

Cartas de:
-> Dois = 2
-> Três = 3
-> Quatro = 4
-> Cinco = 5
-> Seis = 6
-> Sete = 7
-> Oito = 8
-> Nove = 9
-> Valete = V
-> Dama = D
-> Rei = R
-> Às = A


Exemplo de descodificação de ids:

-----------------------------
Output:
array( "T"=>"O" , "C"=>"2" )

Igual a:
Dois de Outros
-----------------------------

*/

function decode_type_name($type)
{
global $ternos;
global $ternos_pt_lang;
return (!$ternos_pt_lang[$type] ? "!invalid" : $ternos_pt_lang[$type]);
}



function decode_card_name($card)
{
global $cartas;
global $cartas_pt_lang;
return (!$cartas_pt_lang[$card] ? "!invalid" : $cartas_pt_lang[$card]);
}




$ternos = array
(
 "E",
 "C",
 "P",
 "O"
);



$cartas = array
(
 "2",
 "3",
 "4",
 "5",
 "6",
 "7",
 "8",
 "9",
 "10",
 "V",
 "D",
 "R",
 "A"
);



$ternos_pt_lang = array
(
 "E" => "Espadas",
 "C" => "Corações",
 "P" => "Paus",
 "O" => "Ouros",
);



$cartas_pt_lang = array
(
 "2" => "Dois",
 "3" => "Três",
 "4" => "Quatro",
 "5" => "Cinco",
 "6" => "Seis",
 "7" => "Sete",
 "8" => "Oito",
 "9" => "Nove",
 "10"=> "Dez",
 "V" => "Valete",
 "D" => "Dama",
 "R" => "Rei",
 "A" => "Às",
);




$baralho = array();
foreach ($cartas as $carta)
{
 foreach ($ternos as $terno)
 {
	  /*
	  * T = tipo de carta (ex:E,C,O)
	  * C = carta (ex:1,2,3,4,5,etc)
	  */
	  $baralho[] = array
	  (
		   "T"=>$terno,
		   "C"=>$carta
	  );
 }
}


shuffle($baralho);// baralha todo o baralho


$n=1;
foreach($baralho as $dados)
{
	  $carta = decode_card_name($dados["C"]); // Descodifica o tipo de carta, ex: (Ás, Valete, etc)
	  $terno = decode_type_name($dados["T"]); // Descodifica o tipo de terno, ex: (Ouros, Paus, Corações,etc)

	  echo $n." - ".$carta."->".$terno."<br>";
	  $n++;
}



?>
Posted

Atribuir valores, secalhar não foi a melhor frase para descrever o que pretendo, básicamente o que pretendo ,é fazer um sistema, baseado neste que comecei, em que seja possível detectar as mãos, ou seja detectar quando acontece um Royal Flush, um Straight, enfim todas as possiblidades que podem acontecer no Poker Texas, e após detectá-las, declarar o vencedor com a melhor mão. Isto requer um trabalho de lógica, só que eu estou "bloqueado" em como irei fazer esse processo todo..

Posted (edited)

Terás de analisar todas as situações possíveis, provavelmente a tentativa e erro é o mais fácil para chegar lá. Precisas também definir a ordem das mãos, para determinar que mão é maior. Começa de cima (mão maior possível) e vai descartando hipóteses. Não tem nada de complicado.

Edited by yoda
Posted

Já é um bom começo, portanto começar pela mão maior, mas podes me dar um exemplo prático (Código) de como isso puderia ser feito? não estou a pedir o código completo obviamente, mas se me pudesses dar um exemplo prático de como seria esse processamento das informações do jogo para o próprio script conseguir decidir quem tem a maior mão, porque no poker existe a possiblidade de 2 jogares terem mãos de potência igual, as cartas para além das mãos têm valor, ou seja o 7 é maio que 6, enfim, são variáveis que não são propriamente líneares e é ai que me faz confusão

Posted (edited)

Mais uma vez, é por tentativa e erro. Um jogador pode até ter mais que uma mão (por exemplo full house e four of a kind, isto para o motor de jogo claro), mas aquilo que interessa é identificar a maior mão do jogador.

Portanto, podes começar por identificar a maior mão de cada jogador, de seguida comparas as mãos. Se existirem 2 ou mais jogadores com mãos idênticas, verificas se algum deles tem uma carta maior que desempate, ou, em caso de mãos como é o exemplo de pares / 2 pares / three of a kind, verificar qual delas é maior. Cada mão tem regras específicas, não perdes nada em ter uma função para tratar cada uma delas, fora o motor principal.

Assim de cabeça, acho que podes identificar as mãos sob estas regras :

- tipo de mão (straight, flush, pair, etc);

- relevância da mão (maior ou menor);

- cartas do jogador (para vias de desempate);

À medida que vais validando cada mão do jogador, vais guardando o resultado num array, e cada vez que validas outro comparas nesse array se a mão desse jogador é maior que alguma das mãos dos outros já validadas.

Edited by yoda
Posted

Estive a estruturar o código, e já está mais próximo, neste momento o script já faz um baralho, dá as cartas aos jogadores, e aparece as cartas do board, o problema é o tal, como vou agora descobrir as mãos de cada jogar baseado no código que escrevi?

Eu fiz upload dos arquivos, podem fazer o download aqui:

http://www.filedropper.com/poker-engine

Eu queria colocar isto em anexo ao post, mas não sei se é possível

Obrigado

Posted

Se tratares cada carta como um par de valores (naipe e numero), em que os numeros vão por exemplo de 2 a 14, podes juntar as cartas de cada jogador num array temporario, e passar uma cadeia if-else a verificar as condições, da maior mão para a menor.

exemplo:

function is_royalflush($cartas, &$kickers){
   # verificar se é royal flush
   # ... se sim, preencher $kickers com as cartas restantes, por ordem de valor decrescente
   # return bool, é royal flush?
}
# ... código aqui pelo meio. possivelmente estas funções sao declaradas noutros ficheiros.
if(is_royalflush($cartas, $kickers)){
   $mao = ROYAL_FLUSH;
}else if(is_fullhouse($cartas, $kickers, $valor)){
   # o mesmo que is_royalflush, mas preenche $valor com o valor  das cartas envolvidas, para desempatar maos iguais.
   $mao = FULL_HOUSE;
}else if(is_3_of_a_kind($cartas, $kickers, $valor)){
   $mao = THREE_OF_A_KIND;
}

Sendo que as constantes se referem a ao valor da mão, em que neste caso ROYAL_FLUSH tem o valor maior.

Se houver uma mão de grande valor, todas as mãos menores são ignoradas.

Podes comparar directamente as mãos ($mao1 > $mao2) para ver qual é maior;

Podes desempatar com o valor da mão, se houver algum para essa mão. Se não houver, podemos meter o valor a -1, só para não passar sem ser declarado...

Finalmente, podes desempatar mãos iguais com valores iguais através dos kickers. Por exemplo, é possivel dois jogadores terem par de Reis, ou Às, neste caso tens de recorrer ao kicker.

É uma questão de teres a logica toda alinhada.

Nota que os kickers são passados como uma referência a um valor (&$var). (funciona +/- como um ponteiro, se o termo te for familiar)

Do meu ponto de vista, é uma forma bastante simples de comparar mãos, com poucas variaveis e o uso de algumas funções simples.

Quanto a guardar os dados do jogo, e tal como o yoda disse, uma base de dados é uma optima opção, senão a melhor, sobretudo se esse motor for lidar com um numero indefinido de jogos simultaneamente e em tempo real...

Posted

Sim esta Classe que estou a desenvolver será para um jogo a correr online-multiplayer, terá uma base de dados claro, mas isso agora para mim é o menos importanto, agora estou focado apenas no motor do jogo e é ai que o meu raciocínio congela, não sei se já fizeram o download do arquivo que deixei ai para darem uma olhadela e para me darem a vossa opinião da estrutura do código, eu acho que está boa, mas pronto para quem não fez o download, eu deixo aqui somente a classe:

poker.php

<?php header('Content-Type: text/html; charset=utf-8');

class Poker
{
 var $language = "pt";// personaliza a língua, pt, es, br, etc.

 var $ternos = array
 (
"E", // E = Espadas
"C", // C = Corações
"P", // P = Paus
"O"  // O = Ouros
 );

 var $hands = array
 (
 "royal-flush"	 => 9,
 "straight-flush"  => 8,
 "four-of-a-kind"  => 7,
 "full-house"	  => 6,
 "flush"		   => 5,
 "straight"		=> 4,
 "three-of-a-kind" => 3,
 "two-pair"		=> 2,
 "one-pair"		=> 1
 );


 var $cartas = array
 (
 "2" => 0.2, // Carta de 2
 "3" => 0.3, // Carta de 3
 "4" => 0.4, // Carta de 4
 "5" => 0.5, // Carta de 5
 "6" => 0.6, // Carta de 6
 "7" => 0.7, // Carta de 7
 "8" => 0.8, // Carta de 8
 "9" => 0.9, // Carta de 9
 "10"=> 1.0, // Carta de 10
 "V" => 1.5, // Carta de Valete
 "D" => 2.0, // Carta de Dama
 "R" => 2.5, // Carta de Rei
 "A" => 10   // Carta de Ás
 );

 var $players			  =	array(); // Onde vai ficar os dados dos jogadores
 var $dealer_board	=	array(); // Onde vai ficar as cartas do dealer
 var $baralho			 =	array(); // Onde vai ficar guardado o baralho
 var $cached_baralhos = array(); // Onde vai ficar guardado o baralho inicial, depois do dealer e depois dos jogadores


 var $cartas_lang = array(); // variável com o nome das cartas
 var $ternos_lang = array(); // variável com o nome dos ternos
 var $hands_lang = array(); // variável com o nome das várias mãos










function __construct($lang=null)
{
 define("POKER_ENGINE","ON");

 if(!$lang)
  $lang = $this->language;

 include("lang/".$lang.".php");

 $this->cartas_lang = $cartas_lang;
 $this->ternos_lang = $ternos_lang;
 $this->hands_lang  = $hands_lang  ;

 $this->CriarBaralho();

}




function CriarBaralho()
{
   foreach ($this->cartas as $carta=>$carta_value)
{
	   foreach ($this->ternos as $terno)
	{
			 /*
	   	  * T = tipo de carta (ex:E,C,O)
			 * C = carta (ex:1,2,3,4,5,etc)
			 * P = valor da carta em números décimais (ex:1.0,0.5,etc)
			 */
			$this->baralho[] = array(
				"T"=>$terno,
				"C"=>$carta,
				"P"=>$carta_value
			 );
	   }
   }

shuffle($this->baralho);

$this->cached_baralhos["first_deck"] = $this->baralho;

$this->MakeDealerCards();
}

function MakeDealerCards()
{
	  $cards=array(
		 rand(0,10),
		 rand(11,21),
		 rand(22,35),
		 rand(36,45),
		rand(46,51)
	  );

 shuffle($cards);

 foreach ($cards as $card_id){
$this->dealer_board[]=$this->baralho[$card_id];
unset($this->baralho[$card_id]);
 }
 $this->baralho=array_values($this->baralho);



  /* TEMPORÁRIO */
  foreach($this->dealer_board as $dados)
	{
		$carta = $this->__DecodeCartaName($dados["C"]); // Descodifica o tipo de carta, ex: (Ás, Valete, etc)
		$terno = $this->__DecodeTernoName($dados["T"]); // Descodifica o tipo de terno, ex: (Ouros, Paus, Corações,etc)

		echo "<div style='float:left; margin-left:20px; text-align:center; font-size:11px;' >
				  <img src='img/cards/".$dados["T"]."_".$dados["C"].".png' />
				  <br />
				  ".$carta."[".$terno."] - ".$dados["P"]."
				   </div>";
	   $n++;
	}

 echo "<br clear='all' /><br /><br />";

/* TEMPORÁRIO */



 $this->cached_baralhos["after_dealer_deck"]=$this->baralho;
}


function AssignPlayers($players_array)
{  
 if(!is_array($players_array))
  die("PKCLASS_9782345H");

 if( count($players_array)> 8 || count($players_array) < 2)
  die("PKCLASS_978UJK");

 foreach($players_array as $player)
 {
  $cards = $this->__GetPlayerCards();
  $total = ($cards[0]["P"] + $cards[1]["P"]);

  $this->players["$player"]["cards"] = $cards;
  $this->players["$player"]["hand"] = $this->__GetPlayerHand($cards);
  $this->players["$player"]["total"] = $total;




	/* TEMPORÁRIO */

   echo "
   <div style='float:left; margin-left:40px;text-align:center; border:1px #666 solid; padding:10px;' >
   $player - ".$total." <br/><br/>
   <img src='img/cards/".$cards[0]["T"]."_".$cards[0]["C"].".png' width='40' align='left' />
   <img src='img/cards/".$cards[1]["T"]."_".$cards[1]["C"].".png' width='40' align='left' />
   <br clear='all' /><br/>
	| ".$this->players["$player"]["hand"]." |<br />
	</div>";


 }
 echo "<br clear='all' /><br clear='all' /><br clear='all' /><br clear='all' />";

 /* TEMPORÁRIO */



 $this->cached_baralhos["after_players_deck"]=$this->baralho;

}


/* TEMPORÁRIO */
/*
function PrintBaralho()
{  
	$n=1;
	foreach($this->baralho as $dados)
	{
		  $carta = $this->__DecodeCartaName($dados["C"]); // Descodifica o tipo de carta, ex: (Ás, Valete, etc)
		  $terno = $this->__DecodeTernoName($dados["T"]); // Descodifica o tipo de terno, ex: (Ouros, Paus, Corações,etc)
		  echo $n." - <img src='img/cards/".$dados["T"]."_".$dados["C"].".png' /><br />".$carta."[".$terno."] - ".$dados["P"]." valor.<br><br />";
		  $n++;
	}
}

/* TEMPORÁRIO */

function __DecodeTernoName($terno)
{  
	  return (!$this->ternos_lang[$terno] ? "!invalid" : $this->ternos_lang[$terno]);  
}
function __DecodeCartaName($card)
{
	 return (!$this->cartas_lang[$card] ? "!invalid" : $this->cartas_lang[$card]);
}



function __GetNumberPlayers()
{
 if(!isset($this->players[0]))
  die("PKCLASS_34554K");

 return count($this->players);
}

function __GetPlayerCards()
{
  $baralho_do_jogo = $this->baralho;
  shuffle($baralho_do_jogo);									// baralha as cartas
  $cards = array( $baralho_do_jogo[0] , $baralho_do_jogo[1]  ); // Seleciona 2 cartas
  unset( $baralho_do_jogo[0] , $baralho_do_jogo[1] );		   // Remove as duas cartas do baralho
  shuffle($baralho_do_jogo);									// baralha novamente as cartas
  $this->baralho=array_values($baralho_do_jogo);				// actualiza o baralho ordenando o seu INDEX
  return $cards ;
}



function __GetPlayerHand($hand)
{  
 $hand_name = null;

 if($hand_name = $this->__Hand_RoyalFlush($hand))
  return $hand_name;
 if($hand_name = $this->__Hand_StraightFlush($hand))
  return $hand_name;
 if($hand_name = $this->__Hand_FourOfaKind($hand))
  return $hand_name;
 if($hand_name = $this->__Hand_FullHouse($hand))
  return $hand_name;
 if($hand_name = $this->__Hand_Flush($hand))
  return $hand_name;
 if($hand_name = $this->__Hand_Straight($hand))
  return $hand_name;
 if($hand_name = $this->__Hand_ThreeOfaKind($hand))
  return $hand_name;
 if($hand_name = $this->__Hand_TwoPair($hand))
  return $hand_name;
 if($hand_name = $this->__Hand_OnePair($hand))
  return $hand_name;

 return "nohand";

}


function __Hand_RoyalFlush($hand)
{
 $this->dealer_board; // as cartas do dealer

 /*
 *  Agora como faço a comparação????
 *
 */

}
function __Hand_StraightFlush($hand)
{
}
function __Hand_FourOfaKind($hand)
{
}
function __Hand_FullHouse($hand)
{
}
function __Hand_Flush($hand)
{
}
function __Hand_Straight($hand)
{
}
function __Hand_ThreeOfaKind($hand)
{
}
function __Hand_TwoPair($hand)
{
}
function __Hand_OnePair($hand)
{
}




/*
function __PrintBaralho()
{
	foreach($this->baralho as $key=>$dados)
	{
	   echo $key."<br />";
	}

}
*/



}
$jogo_1= new Poker();
$players=array("jogador-1","jogador-2","jogador-3","jogador-4","jogador-5","jogador-6","jogador-7","jogador-8");
$jogo_1->AssignPlayers($players);
//$jogo_1->PrintBaralho();

para isto funcionar bem, a classe, façam o download, que traz as imagens das cartas, e o ficheiro de língua PT.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.