用Java制作扑克手牌评估器(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/make-a-poker-hand-evalutator-in-java-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 20 分钟阅读 - 9843 个词 阅读量 0用Java制作扑克手牌评估器(译文)
原文地址:https://www.codeproject.com/Articles/38821/Make-a-poker-hand-evalutator-in-Java
原文作者:CrazyJugglerDrummer
译文由本站 robot-v1.0 翻译
前言
Creates, evalutates, and compares 5-card poker hands.
创建,评估和比较5张牌的扑克手.
介绍(Introduction)
标题说明了一切:制作一个可以创建,评估和比较5张牌扑克手的程序.(The title says it all: make a program that can create, evaluate, and compare 5-card poker hands.)
背景(Background)
本教程可以独立运行,但是如果您需要更多有关在Java中创建卡片组和卡片类的信息,请参见(This tutorial works fine as a stand-alone, but if you want some more information about creating the deck and card class in Java, see) 这里(here) .(.)
使用代码(Using the code)
该程序将能够生成,评估和比较扑克手.需要对OO设计有基本的了解(制作类,并使它们彼此交互).这里没有继承或接口. ;)(This program will be able to generate, evaluate, and compare poker hands. A basic understanding of OO design is required (making classes, and having them interact with one another). No inheritance or interfaces here. ;)) Random
,(,) ArrayList
,有时会使用静态变量和方法,但是如果您不知道它们是什么,它们就不会成为阻碍.我在其中包含了简短的说明(s, and static variables and methods are used on occasions, but they won’t be a show stopper if you don’t know what they are yet. I include quick descriptions in the)**对新手而言:(For beginners:)**笔记.(notes.)
那么我们在OO扑克中需要什么呢?我们有纸牌,副牌和手牌.(So what do we need in OO poker? We have cards, decks, and hands.) Card
将是一个包含(will be a class that contains) rank
和(and) suit
变量(variables,) Deck
将是一个容器(will be a container for) Card
s和(s, and) Hand
将是我们评估和比较扑克手的地方.(will be where we evaluate and compare the poker hands.)
package javapoker;
public class Card{
private short rank, suit;
private static String[] suits = { "hearts", "spades", "diamonds", "clubs" };
private static String[] ranks = { "Ace", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "Jack", "Queen", "King" };
public static String rankAsString( int __rank ) {
return ranks[__rank];
}
Card(short suit, short rank)
{
this.rank=rank;
this.suit=suit;
}
public @Override String toString()
{
return ranks[rank] + " of " + suits[suit];
}
public short getRank() {
return rank;
}
public short getSuit() {
return suit;
}
}
所以我们有只读的(So we have read-only) suit
和(and) rank
变量,简单的构造函数,(variables, a simple constructor, a) toString
方法和(method, and a) rankAsString
方法.该类将非常快,因为它仅通过访问静态数组的索引就知道要输出哪些字符串.该数组用作字典,允许我们转换(method. The class will be ultra fast as it knows which strings to output just by accessing indexes of static arrays. This array functions as a dictionary, allowing us to convert an) int
轻松快捷地将其更改为适当的字符串.我们甚至不必使用(to the appropriate string quickly and easily. We don’t even have to use) String.ParseInt()
.我们本来可以(. We could’ve made a) switch
语句将根据以下内容找到要输出的适当字符串(statement that would find the appropriate string to output based on the) suit
和(and) rank
变量,但每次都必须对其进行评估.以特定索引访问数组要快得多.的(variables, but it would have to evaluate them every time. Accessing an array at a specific index is much faster. The) rankAsString
method是一种实用方法,用于获取数字并将其转换为适合排名的字符串(我们将在以后使用).(method is a utility method for taking a number and turning it into the appropriate string for the rank (we’ll use it later).)
对新手而言(For beginners):关于(: Notes on the) static
关键字:静态方法和变量作为一个整体应用于一个类,而不是像实例方法和变量那样的任何特定实例.我们称之为(keyword: static methods and variables apply to a class as a whole, not any particular instance like instance methods and variables. We call) getRank()
在特定的卡片实例上,使用(on a specific card instance, created with) new
.但是我们会打电话(. But we would call) rankAsString
在课堂上,(on the class, with “) Card.rankAsString( 4 );
“.我们有一个静态数组来表示衣服的不同名称.此数组属于整个类,而不仅仅是一个类(”. We have a static array to represent the different names of the suits. This array belongs to the class as a whole, not just one) Card
,因此可以通过每个实例方法的实例方法进行访问(, so it can be accessed by the instance methods of each) Card
,以及该类的静态方法.(, and by the static methods of the class.)
注意(Note):现在,我们可以使用(: Now, we could’ve used) short
甚至(or even) byte
为了(for the) rank
和(and) suit
变量,因为只有四个可能的值.但是计算机以4字节工作时速度要快得多(variables, since there are only four possible values. But computers work much faster with 4 byte) int
s比2个字节(s than 2 byte) short
s,因此您将在处理速度极快的内存中损失很小的内容.使用(s, so what would be lost in extremely tiny bits of memory you’ll gain in processing speed. Using) int
而不是(s instead of) short
s是Java中的最佳实践.(s is best practice in Java.)
现在我们需要一个甲板来存放我们的卡.我编写了另一个教程,展示了制作牌组的许多不同方法,但是在本教程中,我将仅展示最有效的方法.(Now we need a deck to hold our cards. I’ve made another tutorial showing many different ways of making a deck, but in this tutorial, I’ll just show the most efficient way.)
package javapoker;
import java.util.Random;import java.util.ArrayList;
public class Deck {
private ArrayList<Card> cards;
Deck()
{
cards = new ArrayList<Card>();
int index_1, index_2;
Random generator = new Random();
Card temp;
for (int a=1; a<=4; a++)
{
for (int b=1; b<=13; b++)
{
cards.add( new Card(a,b) );
}
}
int size
for (int i=0; i<100; i++)
{
index_1 = generator.nextInt( cards.size() - 1 );
index_2 = generator.nextInt( cards.size() - 1 );
temp = cards.get( index_2 );
cards.set( index_2 , cards.get( index_1 ) );
cards.set( index_1, temp );
}
}
public Card drawFromDeck()
{
return cards.remove( 0 );
}
public int getTotalCards()
{
return cards.size();
//we could use this method when making
//a complete poker game to see if we needed a new deck
}
}
我们将卡片放入(We put the cards in the) ArrayList
的(of) Card
s,然后随机拿出100对卡片并进行切换,将我们的牌组改组.要从牌组中抽签,我们只需返回第一个元素/牌,然后从牌组中删除该牌.所有随机化都是在构造函数中预先完成的(在实际处理卡片之前),(s, then randomly take 100 pairs of cards and switch them, shuffling our deck. To draw from the deck, we just return the first element/card, and then remove that card from the deck. All the randomization is done beforehand in the constructor (prior to any actual dealing of the cards), making our) drawFromDeck
该方法更简单,处理器占用更少.(method much simpler and less processor intensive.)
初学者注意(Note for beginners):的简短教程(: A brief tutorial of) ArrayList
:(:) ArrayList
是Java中"泛型"的示例.泛型有点像数组,因为它们存储特定类型的对象(<>之间的类型).但(is an example of a “generic” in Java. Generics are sort of like arrays because they store objects of a specific type (the type between the <>). But) ArrayList
是一个对象,而不仅仅是数组,因此它有一些整洁的方法来帮助我们.我们可以自动获得(is an object, not just an array, so it has neat methods to help us out. We can automatically get its size with) size()
,删除或添加对象(, remove or add an object with) remove()
要么(or) add()
,获取并设置对象,如数组(, get and set objects like an array with) get()
和(and) set()
,这也许是最有用的,如果我们需要更多空间,它将为我们自动增长(实际上只是将其项目复制到更大的数组中,但是它可以处理所有这些,因此我们不必这样做).这使得我们通常需要数据结构的功能(例如添加一个新元素)非常易于使用(使用数组将一个新元素添加到末尾,我们必须使索引变量从零开始;每次添加一个位于该索引处的对象,我们将其增加以使其处于新位置,以便我们可以添加更多对象;当然,我们必须希望该数组具有足够的空间;您将在稍后看到此技术).要使用(, and maybe most helpful of all, if we need more space, it will just automatically grow for us (actually just copies its items into a bigger array, but it handles all of this so we don’t have to). This makes features we commonly need with data structures, like adding a new element, really easy to use (with an array, to add a new element to the end, we have to make an index variable that starts at zero; each time we add an object at that index, we increment it to put us at a fresh spot so we can add more objects; of course, we have to hope the array has enough space; you will see this technique used later). To use an) ArrayList
,我们必须导入(, we have to import) java.util.ArrayList
在源文件的顶部.(at the top of the source file.)
初学者注意(Note for beginners): 的总结(: Summary of) Random
:(:) Random
是一个精巧的实用程序类,可用于生成随机数.要使用它,我们导入(is a neat little utility class we can use to generate random numbers. To use it, we import) java.util.Random
,然后随机(, then make a random with) Random generator = new Random()
.完成之后,我们可以使用我们的(. After we do this, we can use our) Random
实例”(instance “) generator
“获得随机(” to get random) int
与(s with) nextInt()
.如果我们将整数传递给(. If we pass an integer to) nextInt()
,它将为我们提供一个小于该整数的随机整数(, it will give us a random integer less than that) int
并大于零.所以当我们打电话(and greater than zero. So when we call) generator.nextInt( 52 );
,它为我们提供了0到51之间的随机数,可以将其用作索引(, it gives us a random number between 0 and 51 that we can use as an index in our) ArrayList
交换两张牌,洗牌.(to swap two cards, shuffling the deck.)
好吧,还算不错,我们有可以将自己描述为绳子的牌,以及可以将其固定在(Okay, that wasn’t so bad, we’ve got cards that can describe themselves as a string and a deck that can hold them in an) ArrayList
并把它们解决.但是现在,我们实际上需要用扑克手来处理它们.持卡机构将类似于卡座,大部分代码将用于评估手的水平.这将非常有趣,请耐心等待.(and deal them out. But now, we actually need to process them in a poker hand. The card holding mechanism will be similar to the deck, the bulk of the code will be in evaluating the hand’s level. This is going to be pretty interesting, so bear with me.)
我们将有5张纸牌和6张纸牌(We’re going to have an array of 5 cards, and an array of 6) int
代表手的价值.首先(s to represent the value of the hand. The first) int
将与手的类型相关,0将是高手牌,1将是一对,对于排名较高的手,其值更大.如果我们平局,则第二个值必须确定获胜者.我们如何找到第二个值对于每种类型的手都是唯一的:在一对中,较高的一对获胜;如果这些值相等,我们将移至下一个确定因素,例如除该对牌外的最高牌或两对手的低牌.有些牌手只有两个决定性因素,例如顺子.第一个值是在扑克手等级中的顺子位置(大于3,少于同花顺),第二个值是顺子中的最高牌(7,杰克,国王等). ).对于高牌,我们将为0,因为高牌是排名最低的一手牌,接下来的5个值将是该牌在手牌中的排名降序.(will correlate to the type of the hand, 0 will be a high card, 1 a pair, with greater values for higher ranked hands. If we have a tie, the second value will have to determine the winner. How we find the second value will be unique to each type of hand: in a pair, the higher pair wins; in a straight, the higher top card wins, etc. If those values are equal, we move onto the next determining factor, like the highest card besides the pair, or the low pair of a two pair hand. Some hands will only have two determining factors, like a straight. The first value would be a straight’s spot in the rank of the poker hands (greater than 3 of a kind, less than a flush), and the second value would be the top card in the straight (7, jack, king, etc.). For a high card, we’d have 0, as high card is the lowest ranked hand, and the next 5 values would be the ranks of the cards in the hand in descending order.)
到目前为止,这里是:(Here’s what we have so far:)
package javapoker;
public class Hand {
private Card[] cards;
private int[] value;
Hand(Deck d)
{
value = new int[6];
cards = new Card[5];
for (int x=0; x<5; x++)
{
cards[x] = d.drawFromDeck(); //fill up cards[] array.
}
//rest of our code to assign values to the value array goes here
}
void displayAll()
{
for (int x=0; x<5; x++)
System.out.println(cards[x]); //calls cards[x].toString()
}
int compareTo(Hand that)
{
for (int x=0; x<6; x++) //cycle through values
{
if (this.value[x]>that.value[x])
return 1;
else if (this.value[x]<that.value[x])
return -1;
}
return 0; //if hands are equal
}
}
好吧,现在通过肮脏的工作,弄清楚我们扑克手的实际价值.让我们从一对情况开始.我们如何确定是否有一对?如果我们有两张相同等级的卡.我们将如何实施呢?我们可以循环浏览各个等级,看看其中是否有两张具有其值的牌.但是,对于3种,我们将不得不再次做同样的事情.我们如何制作一系列(All righty, now with the dirty work, figuring out the actual value of our poker hand. Let’s start with a pair situation. How would we figure out if there is a pair? If we have two cards of the same rank. How will we implement this? We could cycle through the ranks, seeing if any of the ranks has two cards with its value. But then, for 3 of a kind, we’d have to do the same thing again. How about we make an array of) int
s从0开始,带有13个插槽(每个等级一个),然后穿过卡片;对于每张卡,我们增加数组的适当索引.让我们看一下代码表示:(s starting at 0 with 13 slots (one for each rank), then go through the cards; with each card, we increment the appropriate index of the array. Let’s see a code representation:)
(此后的所有代码都放在((All the code from this point on is put in the) Hand
我们的评论所在的构造函数.)(constructor where our comment was.))
int[] ranks = new int[14];
for (int x=0; x<=13; x++)
{
ranks[x]=0; //zero the contents of the array
}
for (int x=0; x<=4; x++)
{
ranks[ cards[x].getRank() ]++;
//increment rank array at the index of each card's rank
}
为了简单起见,我们使用的卡片等级从ace的1开始,而不是ace的0.如果我们使用0表示ace,那么我们将使用9表示10,这很令人困惑.由于我们的卡排名为1-13,因此数组(0)的第一个索引为空.(For simplicity’s sake, we’ve used card ranks starting at 1 for ace instead of 0 for ace. If we use 0 for ace, then we would be using 9 for 10, which is just confusing. Since our card ranks run 1-13, the first index of our array (0) will be empty.)
好的,现在,我们有了纸牌等级数组,现在我们需要确定是否实际上有任何对.我们需要知道是否有一对,如果有,该对的等级是多少.所以我们做一个(Okay, so now, we have our array of card ranks, now we need to find if there are actually any pairs. We need to know if there is a pair, and if there is, what rank the pair is. So we make an) int sameCards
记录多少张相同等级的卡,以及(to record how many cards are of the same rank, and an) int groupRank
保持对的地位.我们做一个(to hold the rank of the pair. We make an) int sameCards
因为我们可能有两张以上相同价值的卡,甚至3或4张(希望不是5张,除非我们的处理器是弯曲的发牌人).我们可以做一个(because we may have more than two cards of the same value, maybe even 3 or 4 (hopefully not 5, unless our processor is a crooked dealer). We could’ve just made a) bool isPair
,但我们想知道是否也有3或4种.(, but we want to know if there is a 3 or 4 of a kind as well.)
int sameCards=1;
//we know there will be at least one card of any rankint groupRank=0;
for (int x=13; x>=1; x--) //loop going from 13 to 1
{
if ( ranks[x] > sameCards) //If more cards of rank x than sameCards
{
sameCards=ranks[x]; //set sameCards to that number of cards
groupRank=x; //and record the rank of the cards
}
}
sameCards
从1开始,所以如果我们找到一个有两张牌的等级,那么我们将2记录在(starts at 1, so if we find a rank of which there are two cards, then we record 2 in) sameCards
和(and) rank (x)
如(as) groupRank
.如果有一对,三个或四个,这将很好地工作.(. This will work fine if there’s a pair, three of a kind, or four of a kind.)
但请稍等,假设我们有一个满屋子.有一对国王,所以我们记录2为(But wait a second, let’s say we have a full house. There is a pair of kings, so we record 2 as) sameCards
和13作为(and 13 as) groupRank
.但是我们继续进行其他排名,如果有3个5,那么我们将覆盖(. But we keep going through the other ranks, and if there are 3 fives, then we overwrite) sameCards
用3表示,因为该等级的卡牌数量大于的当前值(with 3 since the number of cards of that rank is more than the current value of) sameCards
.类似的情况:我们有两对,它记录了第一对,但没有另一对.我们可以用一组纸牌来做牌,但是不能用2张纸.我们需要一种方法来跟踪至少两个不同的牌组,跟踪牌的数量和等级.在继续之前先考虑一下.(. Similar situation: we have two pairs, it records the first pair, but not the other one. We can do hands with one group of cards, but not hands with 2. We need a way to keep track of at least two different groups of cards, tracking the number of cards and the rank of each. Think about it a bit before moving on.)
注意(Note):这绝对是程序中最密集的逻辑,因此,如果您一开始不明白这一点,请不要担心.其余的代码都稍微容易一些,您可以稍后再回到这一部分. :)(: this is definitely the most intense logic of the program, so if you don’t get this at first, don’t worry. The rest of the code is all a little easier, and you can come back to this part later. :))
我的解决方案:好的,我们必须跟踪两个纸牌等级以及每个等级有多少张牌,因此我们将有两个变量来表示等级((My solution: all right, we have to keep track of two ranks of cards and how many cards are of each rank, so we’ll have two variables to represent the ranks () largeGroupRank
,(,) smallGroupRank
)和两个代表该等级的纸牌数量(() and two to represent the number of cards that have that rank () sameCards
,(,) sameCards2
).().)
int sameCards=1,sameCards2=1;
//initialze to 1int largeGroupRank=0,smallGroupRank=0;
for (int x=13; x>=1; x--)
{
if (ranks[x] > sameCards)
{
if (sameCards != 1)
//if sameCards was not the default value
{
sameCards2 = sameCards;
smallGroupRank = largeGroupRank;
}
sameCards = ranks[x];
largeGroupRank = x;
} else if (ranks[x] > sameCards2)
{
sameCards2 = ranks[x];
smallGroupRank = x;
}
}
如果(If) ranks[x]
大于(is greater than) sameCards
,我们在那里分配数据;否则,如果大于(, we assign the data there; otherwise, if it is greater than) sameCards2
,我们在那里分配数据.现在,我确定大家都看到了嵌套(, we assign the data there. Now, I’m sure you all saw the nested) if
,所以我想最好告诉您它的用途.说(, so I guess I might as well tell you what it is for. Say the) if
不存在:我们找到一对8,然后发现三个5.(wasn’t there: we find a pair of 8’s, then we find three 5’s.) sameCards
包含一对8,并且由于三个5大于两个8,因此我们覆盖(contains the pair of 8’s, and since the three 5’s is more than the two 8’s, we overwrite) sameCards
.但是我们早先发现的那对应该被覆盖,只是被覆盖而未在任何地方记录(. But the pair we found earlier is just overwritten and not recorded anywhere, when it should have been stuck into) sameCards2
.所以(. So, the) if
语句检查是否(statement checks if) sameCards
在覆盖之前已被分配给某个东西,如果是的话,我们会处理.(was previously assigned to something before overwriting it, and if it was, we take care of that.)
样本运行:我们找到2个皇后,因此我们将该值记录在(Sample run: We find 2 queens, so we record that value in) sameCards
,因为2大于我们初始化的1(, since 2 is more than the 1 we initialized) sameCards
用.然后,我们找到2个7,所以我们将其记录在(with. Then, we find 2 7’s, so we record that in) sameCards2
.我们找到3个千斤顶,记录在(. We find 3 Jacks, record those in) sameCards
,然后找到2个三分,所以我们将它们记录在(, then find 2 threes, so we record them in) sameCards2
.两个8,然后三个4.我们将两个8的数据写入(. Two 8’s, then three 4’s. We write the data from the two 8’s into) sameCards2
,然后将三个4的数据放入(, then put the data from the three 4’s into) sameCards1
.一切都很好 :).(. All is well :).)
还有更多的事情要走,但是你已经走过了.其余代码从这里都是下坡路.(There’s a little more to go, but you’ve made it over the hill; the rest of the code is all downhill from here.)
呜呜!我们已经编写了代码来确定一对,两对,三个同类型,四个同类型和一个满屋子.剩下要做的决定是我们是否有同花或同花.(Woo hoo! We’ve written the code to determine a pair, 2 pairs, three of a kind, four of a kind, and a full house. The determinations left to do is whether we have a flush or a straight.)
让我们先冲洗一下.我们如何确定所有牌是否都相同?好吧,如果两张卡不是同一套衣服,那么就不会有同花顺,所以让我们尝试一下.我们搭便车,循环遍历记录其等级的卡片:(Let’s do a flush first. How do we find out if all the cards are the same suit? Well, if two cards are not the same suit, then there’s no flush, so let’s try this. We hitch a ride on the loop that iterates through the cards recording their ranks:)
boolean flush=true; //assume there is a flush
for (int x=0; x<4; x++)
{
if ( cards[x].getSuit() != cards[x+1].getSuit() )
flush=false;
}
Okey dokey,穿梭于各张牌中,如果其中一套与下一张牌不符,则没有同花.(Okey dokey, travel through the cards, and if one of their suits doesn’t match the suit of the next card, then there' no flush.) 为了弄清楚是否有顺子,我们需要知道是否连续有五张牌.因此,如果连续五个排名中有一张牌,我们就有顺子.(To figure out if there’s a straight, we need to know if there are five cards in a row. So, if there is one card in five5 consecutive ranks, we have a straight.)
int topStraightValue=0;boolean straight=false; //assume no straight
for (int x=1; x<=9; x++) //can't have straight with lowest value of more than 10
{
if (ranks[x]==1 && ranks[x+1]==1 && ranks[x+2]==1 &&
ranks[x+3]==1 && ranks[x+4]==1)
{
straight=true;
topStraightValue=x+4; //4 above bottom value
break;
}
}
if (ranks[10]==1 && ranks[11]==1 && ranks[12]==1 &&
ranks[13]==1 && ranks[1]==1) //ace high
{
straight=true;
topStraightValue=14; //higher than king
}
我们检查是否有一张连续5个等级的卡片.有一个循环可以直达国王,我们添加了一个特殊的分隔符(We check to see if there is one card of 5 consecutive ranks. There’s a loop to do straights up to king high, and we add a special separate) if
对于A的高直牌,因为A的数量包含在(for an ace high straight, since the number of aces is contained in) ranks[1]
.(.)
是的,我们涵盖了所有不同类型的手!现在,我们需要开始比较它们.我们需要确定手的类型,但仍然需要更多数据来固定手之间的关系.假设我们有一对,我们知道一对是排名第二低的牌.如果我们要比较的那只手也是一对,那么我们需要比较这对的等级.如果货币对的等级相等,则需要转到下一张最高的卡,然后是下一张最高的卡,再到下一张最高的卡.现在我们唯一需要的是顺序最高的卡片.(Yay, we’ve covered all the different types of hands! Now, we need to start comparing them. We have what we need to determine the type of the hand, but we still need a little more data to fix ties between hands. Say we have a pair, we know that a pair is the second lowest ranked hand. If the hand we’re comparing it to is also a pair, then we need to compare the rank of the pair. If the rank of the pair is equal, we need to go to the next highest card, then the next highest card, and then the next highest card. The only thing we need now is the next highest cards in order.)
int[] orderedRanks = new int[5];
int index=0;
if (ranks[1]==1) //if ace, run this before because ace is highest card
{
//record an ace as 14 instead of one, as its the highest card
orderedRanks[index]=14;
index++; //increment position
}
for (int x=13; x>=2; x--)
{
if (ranks[x]==1)
//we have already written code to handle the case
//of their being two cards of the same rank
{
orderedRanks[index]=x;
index++;
}
}
现在,我们有了一个数组,该数组将容纳所有其他的卡. (w00t!)(Now we have an array that will hold all the miscellaneous cards that don’t mean anything else. (w00t!))
在我们的(In our) Hand
类中,我们有一个私有数组值,其中包含六个(class, we have a private array value that holds six) int
s.我们将使用它来包含手的值.该数组将保存比较两个扑克手所需的所有数据.我之前提到过我们进行比较的过程:“说我们有一对,我们知道一对是排名第二低的手.如果我们要比较的那只手也是一对,那么我们需要比较该对的排名.如果配对的等级相等,我们需要转到下一张最高的牌,然后是第二张最高的牌,再到第二张最高的牌."(s. We are going to use this to contain the values of the hands. This array will hold all the data necessary to compare two poker hands. I mentioned our process of comparing before: “Say we have a pair, we know that a pair is the second lowest ranked hand. If the hand we’re comparing it to is also a pair, then we need to compare the rank of the pair. If the rank of the pair is equal, we need to go to the next highest card, then the next highest card, and then the next highest card.")
这列出了我们需要比较的东西.最重要的是哪种手,所以将处于第一位置.其余位置将保留打破相同类型的两只手之间的平局所需的数据.看一看:(This sets up a list of the things we need to compare. The most important thing is what kind of hand, so that will go in the first position. The rest of the positions will hold the data needed to break a tie between two hands of the same type. Take a look:)
//start hand evaluation
if ( sameCards==1 ) { //if we have no pair...
value[0]=1; //this is the lowest type of hand, so it gets the lowest value
value[1]=orderedRanks[0]; //the first determining factor is the highest card,
value[2]=orderedRanks[1]; //then the next highest card,
value[3]=orderedRanks[2]; //and so on
value[4]=orderedRanks[3];
value[5]=orderedRanks[4];
}
if (sameCards==2 && sameCards2==1) //if 1 pair
{
value[0]=2; //pair ranked higher than high card
value[1]=largeGroupRank; //rank of pair
value[2]=orderedRanks[0]; //next highest cards.
value[3]=orderedRanks[1];
value[4]=orderedRanks[2];
}
if (sameCards==2 && sameCards2==2) //two pair
{
value[0]=3;
//rank of greater pair
value[1]= largeGroupRank>smallGroupRank ? largeGroupRank : smallGroupRank;
//rank of smaller pair
value[2]= largeGroupRank<smallGroupRank ? largeGroupRank : smallGroupRank;
value[3]=orderedRanks[0]; //extra card
}
if (sameCards==3 && sameCards2!=2)
//three of a kind (not full house)
{
value[0]=4;
value[1]= largeGroupRank;
value[2]=orderedRanks[0];
value[3]=orderedRanks[1];
}
if (straight)
{
value[0]=5;
value[1]=;
//if we have two straights,
//the one with the highest top cards wins
}
if (flush)
{
value[0]=6;
value[1]=orderedRanks[0]; //tie determined by ranks of cards
value[2]=orderedRanks[1];
value[3]=orderedRanks[2];
value[4]=orderedRanks[3];
value[5]=orderedRanks[4];
}
if (sameCards==3 && sameCards2==2) //full house
{
value[0]=7;
value[1]=largeGroupRank;
value[2]=smallGroupRank;
}
if (sameCards==4) //four of a kind
{
value[0]=8;
value[1]=largeGroupRank;
value[2]=orderedRanks[0];
}
if (straight && flush) //straight flush
{
value[0]=9;
value[1]=;
}
因此,既然我们已经设置了所有的值数组(那是(So now that we have all of our value array set up (that was the end of the) Hand
构造函数),我们可以使用此方法将我们的手与任何其他手进行比较:(constructor), we can use this method to compare our hand to any other hand:)
int compareTo(Hand that)
{
for (int x=0; x<6; x++)
{
if (this.value[x]>that.value[x])
return 1;
else if (this.value[x] != that.value[x])
//if not greater and not equal, must be less
return -1;
}
return 0; //if hands are equal
}
并且,我们可以添加此方法以显示手的摘要(这也是我们使用静态(And, we can add this method to display a summary of the hand (this is also where we use the static) rankAsString
中的方法(method in the) Card
类,以将整数转换为附属卡等级,例如11 =” Jack”).(class to convert an integer to an associate card rank, e.g., 11 = “Jack”).)
void display()
{
String s;
switch( value[0] )
{
case 1:
s="high card";
break;
case 2:
s="pair of " + Card.rankAsString(value[1]) + "\'s";
break;
case 3:
s="two pair " + Card.rankAsString(value[1]) + " " +
Card.rankAsString(value[2]);
break;
case 4:
s="three of a kind " + Card.rankAsString(value[1]) + "\'s";
break;
case 5:
s=Card.rankAsString(value[1]) + " high straight";
break;
case 6:
s="flush";
break;
case 7:
s="full house " + Card.rankAsString(value[1]) +
" over " + Card.rankAsString(value[2]);
break;
case 8:
s="four of a kind " + Card.rankAsString(value[1]);
break;
case 9:
s="straight flush " + Card.rankAsString(value[1]) + " high";
break;
default:
s="error in Hand.display: value[0] contains invalid value";
}
s = " " + s;
//this just moves the output over a little in the console
//so its easier to see when viewing the output
System.out.println(s);
}
现在已经完成了详尽的类,我们可以编写一些测试代码,并在工作中看到这些东西.我们的第一个主要方法将测试我们制作的套牌的随机性(在上一教程中有更多讨论).(Now that that exhaustive class is done, we can write some test code and see this stuff at work. Our first main method will test the randomness of the deck we made (discussed more in the past tutorial).)
package javapoker
public class Main {
public static void main(String[] args)
{
Deck deck= new Deck();
Card C;
System.out.println( deck.getTotalCards() );
while (deck.getTotalCards()!=0 )
{
C = deck.drawFromDeck();
System.out.println( C.toString() );
}
}
}
好的,它看起来足够随机,所以现在让我们尝试动手做一下,看看程序认为它们排名如何,然后将其与我们知道应该排名的内容进行比较:(OK, that looks random enough, so now, let’s try making some hands and seeing what the program thinks they are ranked, and compare that to what we know they should be ranked:)
public static void main(String[] args) {
for (int i=0; i<100; i++)
{
Deck deck= new Deck();
Hand hand= new Hand(deck);
hand.display(); //show the summary of the hand, e.g. "full house"
hand.displayAll(): //look at all the individual cards in the hand
}
}
好的,最后一种测试机制是手进行比较,并使用类似的方法:(All righty, last mechanism to test is the hand comparing, with a similar method:)
public static void main(String[] args) {
for (int i=0; i<20000; i++)
{
Deck deck= new Deck();
Hand hand= new Hand(deck);
Hand hand2= new Hand(deck);
hand.display();
hand.displayAll();
hand2.display();
hand2.displayAll();
System.out.println(hand.compareTo(hand2));
}
}
到那里,如何用Java制作扑克手牌评估器!希望您喜欢本教程!请发布所有评论,问题和建议! :)(And there you have it, how to make a poker hand evaluator in Java! I hope you’ve enjoyed this tutorial! Please post any and all comments, questions, and suggestions! :)) 注意(Note):本教程仅介绍如何制作,评估和比较扑克手(我认为这足以完成一个教程).它实际上并没有告诉我们如何制作一个完全可玩的扑克游戏.进行下注并不是那么困难,但是使现实的对手所涉及的AI不在此范围之内.但是,这是扑克游戏的良好基础,如果有人用良好,逼真的AI和游戏玩法完成了扑克游戏,他们可以继续并在CodeProject上发布该文章.(: This tutorial only covers how to make, evaluate, and compare poker hands (which I think was enough for one tutorial). It does not actually tell how to make a full playable poker game. Making betting wouldn’t be that difficult, but the AI involved for making realistic opponents is beyond this scope. This is a good basis for a poker game however, and if anyone completes the poker game with good, realistic AI and gameplay, they can go ahead and post that article on CodeProject.)
代码(The code)
这是教程中每个类的完整代码(用于粘贴到编译器中):(Here is the full code for each of the classes in the tutorial (for pasting into a compiler):) Card.java(Card.java)```java package javapoker; public class Card{ private short rank, suit;
private static String[] suits = { “hearts”, “spades”, “diamonds”, “clubs” }; private static String[] ranks = { “Ace”, “2”, “3”, “4”, “5”, “6”, “7”, “8”, “9”, “10”, “Jack”, “Queen”, “King” };
public static String rankAsString( int __rank ) { return ranks[__rank]; }
Card(short suit, short rank) { this.rank=rank; this.suit=suit; }
public @Override String toString() { return ranks[rank] + " of " + suits[suit]; }
public short getRank() { return rank; }
public short getSuit() { return suit; } }
Deck.java(*Deck.java*)```java
package javapoker;
import java.util.Random;import java.util.ArrayList;
public class Deck {
private ArrayList<Card> cards;
Deck()
{
cards = new ArrayList<Card>();
int index_1, index_2;
Random generator = new Random();
Card temp;
for (short a=0; a<=3; a++)
{
for (short b=0; b<=12; b++)
{
cards.add( new Card(a,b) );
}
}
int size = cards.size() -1;
for (short i=0; i<100; i++)
{
index_1 = generator.nextInt( size );
index_2 = generator.nextInt( size );
temp = (Card) cards.get( index_2 );
cards.set( index_2 , cards.get( index_1 ) );
cards.set( index_1, temp );
}
}
public Card drawFromDeck()
{
return cards.remove( cards.size()-1 );
}
public int getTotalCards()
{
return cards.size();
//we could use this method when making
//a complete poker game to see if we needed a new deck
}
}
Hand.java(Hand.java)```java package javapoker; public class Hand { private Card[] cards; private int[] value;
Hand(Deck d) { value = new int[6]; cards = new Card[5]; for (int x=0; x<5; x++) { cards[x] = d.drawFromDeck(); }
int[] ranks = new int[14];
//miscellaneous cards that are not otherwise significant
int[] orderedRanks = new int[5];
boolean flush=true, straight=false;
int sameCards=1,sameCards2=1;
int largeGroupRank=0,smallGroupRank=0;
int index=0;
int topStraightValue=0;
for (int x=0; x<=13; x++)
{
ranks[x]=0;
}
for (int x=0; x<=4; x++)
{
ranks[ cards[x].getRank() ]++;
}
for (int x=0; x<4; x++) {
if ( cards[x].getSuit() != cards[x+1].getSuit() )
flush=false;
}
for (int x=13; x>=1; x--)
{
if (ranks[x] > sameCards)
{
if (sameCards != 1)
//if sameCards was not the default value
{
sameCards2 = sameCards;
smallGroupRank = largeGroupRank;
}
sameCards = ranks[x];
largeGroupRank = x;
} else if (ranks[x] > sameCards2)
{
sameCards2 = ranks[x];
smallGroupRank = x;
}
}
if (ranks[1]==1) //if ace, run this before because ace is highest card
{
orderedRanks[index]=14;
index++;
}
for (int x=13; x>=2; x--)
{
if (ranks[x]==1)
{
orderedRanks[index]=x; //if ace
index++;
}
}
for (int x=1; x<=9; x++)
//can't have straight with lowest value of more than 10
{
if (ranks[x]==1 && ranks[x+1]==1 && ranks[x+2]==1 &&
ranks[x+3]==1 && ranks[x+4]==1)
{
straight=true;
topStraightValue=x+4; //4 above bottom value
break;
}
}
if (ranks[10]==1 && ranks[11]==1 && ranks[12]==1 &&
ranks[13]==1 && ranks[1]==1) //ace high
{
straight=true;
topStraightValue=14; //higher than king
}
for (int x=0; x<=5; x++)
{
value[x]=0;
}
//start hand evaluation
if ( sameCards==1 ) {
value[0]=1;
value[1]=orderedRanks[0];
value[2]=orderedRanks[1];
value[3]=orderedRanks[2];
value[4]=orderedRanks[3];
value[5]=orderedRanks[4];
}
if (sameCards==2 && sameCards2==1)
{
value[0]=2;
value[1]=largeGroupRank; //rank of pair
value[2]=orderedRanks[0];
value[3]=orderedRanks[1];
value[4]=orderedRanks[2];
}
if (sameCards==2 && sameCards2==2) //two pair
{
value[0]=3;
//rank of greater pair
value[1]= largeGroupRank>smallGroupRank ? largeGroupRank : smallGroupRank;
value[2]= largeGroupRank<smallGroupRank ? largeGroupRank : smallGroupRank;
value[3]=orderedRanks[0]; //extra card
}
if (sameCards==3 && sameCards2!=2)
{
value[0]=4;
value[1]= largeGroupRank;
value[2]=orderedRanks[0];
value[3]=orderedRanks[1];
}
if (straight && !flush)
{
value[0]=5;
value[1]=;
}
if (flush && !straight)
{
value[0]=6;
value[1]=orderedRanks[0]; //tie determined by ranks of cards
value[2]=orderedRanks[1];
value[3]=orderedRanks[2];
value[4]=orderedRanks[3];
value[5]=orderedRanks[4];
}
if (sameCards==3 && sameCards2==2)
{
value[0]=7;
value[1]=largeGroupRank;
value[2]=smallGroupRank;
}
if (sameCards==4)
{
value[0]=8;
value[1]=largeGroupRank;
value[2]=orderedRanks[0];
}
if (straight && flush)
{
value[0]=9;
value[1]=;
}
}
void display() { String s; switch( value[0] ) {
case 1:
s="high card";
break;
case 2:
s="pair of " + Card.rankAsString(value[1]) + "\'s";
break;
case 3:
s="two pair " + Card.rankAsString(value[1]) + " " +
Card.rankAsString(value[2]);
break;
case 4:
s="three of a kind " + Card.rankAsString(value[1]) + "\'s";
break;
case 5:
s=Card.rankAsString(value[1]) + " high straight";
break;
case 6:
s="flush";
break;
case 7:
s="full house " + Card.rankAsString(value[1]) + " over " +
Card.rankAsString(value[2]);
break;
case 8:
s="four of a kind " + Card.rankAsString(value[1]);
break;
case 9:
s="straight flush " + Card.rankAsString(value[1]) + " high";
break;
default:
s="error in Hand.display: value[0] contains invalid value";
}
s = " " + s;
System.out.println(s);
}
void displayAll() { for (int x=0; x<5; x++) System.out.println(cards[x]); }
int compareTo(Hand that) { for (int x=0; x<6; x++) { if (this.value[x]>that.value[x]) return 1; else if (this.value[x]<that.value[x]) return -1; } return 0; //if hands are equal } }
## 兴趣点(*Points of interest*)
当我观看该程序评估并比较200,000张扑克牌时,我真的感到很有力量,就像我已经完成了一些事情一样.我不可能在10年内做到这一点,但是计算机在不到一分钟的时间内就做到了.(*When I was watching this program evaluate and compare 200,000 poker hands, I really felt powerful, like I had accomplished something. I couldn't have done that in 10 years, but the computer did it in a bit more than a minute.*)
## 历史(*History*)
- 8-7-09:提交的文章.(*8-7-09: Submitted article.*)
## 许可
本文以及所有相关的源代码和文件均已获得[The Code Project Open License (CPOL)](http://www.codeproject.com/info/cpol10.aspx)的许可。
Java
Dev
新闻
翻译