モチベーションと目的
Javaについて少し知っておこうと思い6/21から勉強を始めました。
6/21にprogateでJavaの基礎的なことは学んだのでアウトプットしようと思います。
作るのは何でもよかったのですが、私が愛してやまない頭脳スポーツ「テキサスホールデム」を作ってみようと思います。
就職に向けてアウトプットソースを増やす目的と、日記的な意味合いで学習の軌跡をここにメモっておくことにしました。
予定
1日目:progateでJavaについて知る(割愛)
2,3日目:とりあえず実装(できた!)
4日目:オブジェクト指向に倣いコードを整える(無理かも)
実装機能(簡単のため相当簡略化)
昨日は
カードを配り、プリフロップのアクションを決定
するところまでできていた
残すところ
フロップ、ターン、リバーの動き
ハンドの強弱、役の決定
all-in、foldなどの処理
です
ハンドの強弱
一番頭を悩ませたハンドの役の決定から。
なお、簡単のためフラッシュ、ストレートは今回実装しなかった。また、最弱のカードは2ではなくAになってるが勘弁してほしい。以下のように考えた。
昨日に引き続き配列にフラグを詰め込むことでなんとか実現した。
public static int[] handRank(int array[]) {
int count[] = {0,0,0,0,0,0,0,0,0,0,0,0,0};
for(int i : array) {
count[i-1] = count[i-1] + 1;
}
int hand[] = new int[6];
int newCount[] = count.clone();
int pairNumber1;
int pairNumber2;
Arrays.sort(newCount);
if(newCount[12] == 1) {
//System.out.println("hicard");
Arrays.sort(array);
System.arraycopy(array, 2, hand, 0, 5);
return hand;
}else if(newCount[12] == 2 && newCount[11] == 1) {
//System.out.println("pair");
pairNumber1 = handNumber(count, 2).get(0);
pairHand(array, pairNumber1, hand);
return hand;
}else if(newCount[12] == 2 && newCount[11] == 2) {
//System.out.println("two-pair");
pairNumber1 = handNumber(count, 2).get(0);
pairNumber2 = handNumber(count, 2).get(1);
twoPairHand(array, pairNumber1,pairNumber2, hand);
return hand;
}else if(newCount[12] == 3 && newCount[11] == 1) {
//System.out.println("three-card");
pairNumber1 = handNumber(count, 3).get(0);
threePairHand(array, pairNumber1, hand);
return hand;
}else if(newCount[12] == 3 && newCount[11] == 2 || newCount[11] == 3) {
//System.out.println("full-house");
pairNumber1 = handNumber(count, 3).get(0);
pairNumber2 = handNumber(count, 2).get(0);
fullHouseHand(pairNumber1, pairNumber2, hand);
return hand;
}else if(newCount[12] == 4) {
//System.out.println("four-card");
pairNumber1 = handNumber(count, 4).get(0);
fourCard(array, pairNumber1, hand);
return hand;
}
return hand;
}
各分岐内のメソッドでは、7枚の中から一番強い手札になるように5枚選んでhandに格納する処理が行われる。
ペアなどの役ありの数字をまず入れて、残りを数字の大きい順に詰めていくようにした。
public static void twoPairHand(int array[], int pairNumber1, int pairNumber2, int hand[]) {
Arrays.sort(array);
int handNum = 0;
int i = 6;
while(handNum < 1) {
if(array[i] != pairNumber1 && array[i] != pairNumber2) {
hand[handNum] = array[i];
i --;
handNum ++;
}else {
i --;
}
}
フロップ、ターン、リバーの動き
int list[] にフォールドフラグと、オールインフラグを追加、これらが立っている場合は各ストリートをスキップし、いきなりショウダウンになるようにした。
int list[] = {1000,1000,0,0,0,0};
//[0] herochip(自分)/
//[1] enemychip(相手)/
//[2] pot/
//[3] needChiptoCall
//[4]foldFlag
//===foldFlag===
// 0 foldしてない
// 1 heroがfold
// 2 enemy がfold
//[5]alInFlag
//===allInFlag===
// 0 allinしてない
// 1 heroがallin
// 2 enemy がallin
streetメソッドにはストリートにおける自分のアクション、相手のアクションを行う処理が入っている。
//プリフロップの処理
street(hero, list, scan);
//ターン、リバーの処理
//フロップ3枚追加
if(list[4] == 0 && list[5] == 0) {
System.out.println("フロップは" + toDescription(holeCard.get(0)) + toDescription(holeCard.get(1)) +toDescription(holeCard.get(2)) + "です");
street(hero, list, scan);
}
//ターン
if(list[4] == 0 && list[5] == 0) {
System.out.println("ターンカードは" + toDescription(holeCard.get(3)) + "です。ホールカードは"+ toDescription(holeCard.get(0)) + toDescription(holeCard.get(1)) +toDescription(holeCard.get(2)) +toDescription(holeCard.get(3)) + "です");
street(hero, list, scan);
}
//リバー
if(list[4] == 0 && list[5] == 0) {
System.out.println("リバーカードは" + toDescription(holeCard.get(4)) + "です。ホールカードは"+ toDescription(holeCard.get(0)) + toDescription(holeCard.get(1)) +toDescription(holeCard.get(2)) +toDescription(holeCard.get(3)) + toDescription(holeCard.get(4)) + "です");
street(hero, list, scan);
}
//ショーダウン。勝敗の決定
if(list[4] == 1) {//heroが降りた時
System.out.println("enemyは"+list[2]+"$のチップを獲得しました" );
list[1] = list[1] + list[2];
list[2] = 0;
list[3] = 0;
list[4] = 0;
}else if(list[4] == 2) {
System.out.println("heroは"+list[2]+"$のチップを獲得しました" );
list[0] = list[0] + list[2];
list[2] = 0;
list[3] = 0;
list[4] = 0;
}else {
int herorole[] = showdown(hero, holeCard);
int enemyrole[] = showdown(enemy, holeCard);
System.out.println("ショウダウンです。ホールカードは"+ toDescription(holeCard.get(0)) + toDescription(holeCard.get(1)) +toDescription(holeCard.get(2)) +toDescription(holeCard.get(3)) + toDescription(holeCard.get(4)) + "です");
System.out.println("hero : " + toDescription(hero.get(0)) + toDescription(hero.get(1)) + role(herorole[5]));
System.out.println("enemy : " + toDescription(enemy.get(0)) + toDescription(enemy.get(1)) + role(enemyrole[5]));
checkWinner(herorole, enemyrole, list);
}
実行結果
1ハンドで終わってますが、どちらかのチップが0になるまでゲームは続くようになっています。
セッションを開始します!グッドラック!
==========1ハンド目===========
あなたのハンドは♣8♣4です
あなたの所持チップは1000です。相手の所持チップは1000です
ポットは0です
アクションを選択してください check : c or bet : b
b
いくらベットしますか?最大1000です
10
10$ベットしました
ememyは20$にレイズしました。
あなたのハンドは♣8♣4です
あなたの所持チップは990です。相手の所持チップは980です
ポットは30です
アクションを選択してください call : c or raise : r or fold : f
c
callしました。
次のストリートに進みます
フロップは♥2♦8♥3です
あなたのハンドは♣8♣4です
あなたの所持チップは980です。相手の所持チップは980です
ポットは40です
アクションを選択してください check : c or bet : b
b
いくらベットしますか?最大980です
980
Allinです
980ベットしました
enemyはcallしました。All-inです
次のストリートに進みます
ショウダウンです。ホールカードは♥2♦8♥3♣10♥Jです
hero : ♣8♣4ワンペア
enemy : ♦7♠7ワンペア
勝者はhero!役はワンペア キッカーは8
heroは2000のチップを獲得しました
ゲーム終了です。お疲れ様でした。
さいごに
配列は要素からインデックスを取り出すこともできないし、色々使い勝手が悪いのかなと思った。リストを優先して使ったほうがいいのかな?
600行を超えるコードを一気に書いたのは初めてだったので非常に疲れた。解説が超適当になってしまっている。これ一か月後に見返しても全然理解できないんだろうな・・・。
でも、かなり簡略化しているとはいえ、一昨日hello worldしてた自分が動くものを作れたことに感動している。明日大学の課題が順調に消化できたらオブジェクト指向の書き方を学んで書き直そうかと思います。
寝違えた首がまだ痛いいいいいいいいいいいい
それにしてもquitaって結構読まれるんですね・・・view数に驚きました。
ソースコードは以下
https://github.com/hmck8625/poker/blob/master/poker.java