
【ゲーム】JavaScript:07 ポーカー対戦ゲーム
このゲームは、プレイヤーとコンピュータがそれぞれ5枚ずつ手札を持ち、ワンペアやストレート、フラッシュなどのポーカー役を競うシンプルな対戦型カードゲームです。手札を配ってから一度だけ任意の枚数を交換し、最終手役を比較して勝敗を決定します。
遊び方と操作方法
「🃏 ゲーム開始」ボタンを押すとカードが配られ、プレイヤーの手札が白抜きで、コンピュータの手札は裏向き(🂠)で表示されます。
- カードをクリックすると選択状態(青背景)になり、交換可能なカードを指定できます。
- 「♻️ カード交換」ボタンで選択したカードを山札から同数引き直せます(一度だけ)。
- 交換後は「🔍 結果を見る」ボタンでコンピュータの手札を表向きにし、役を判定して勝敗を表示。
- 「🔄 ゲームをリセット」でいつでも初期状態に戻せます。
ルール
- 5枚配られた手札から好きな枚数だけ交換可能(交換は1回限り)。
- 交換後、両者の手役(ロイヤルストレートフラッシュ~ハイカード)を比べ、強いほうが勝利。
- 同じ手役なら「引き分け」。役の強さは「ロイヤル… > ストレートフラッシュ > … > ハイカード」の順。
🎮ゲームプレイ
以下のリンク先から実際にプレイできます。
07 ポーカー対戦ゲーム
素材のダウンロード
以下のリンクから使用する素材をダウンロードできます。
poker_bg.png |
---|
![]() |
ゲーム画面イメージ

プログラム全文(poker.html)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🃏 ポーカー対戦ゲーム 🃏</title>
<style>
/* 全体スタイル */
body {
margin: 0;
padding: 0;
font-family: 'Arial', sans-serif;
text-align: center;
background: url('poker_bg.png') no-repeat center center fixed;
background-size: cover;
color: white;
}
/* タイトル・見出しを読みやすく */
h1, h2 {
display: inline-block;
background: rgba(0, 0, 0, 0.6);
padding: 10px 20px;
border-radius: 8px;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.7);
}
h1 { font-size: 2.5em; margin: 20px 0; }
h2 { font-size: 1.8em; margin: 20px 0; }
/* カードコンテナ */
.cards {
display: flex;
justify-content: center;
margin: 20px;
}
/* カードの見た目 */
.card {
width: 80px;
height: 120px;
border-radius: 10px;
border: 2px solid #fff;
margin: 5px;
font-size: 20px;
line-height: 120px;
font-weight: bold;
text-align: center;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.3);
background-color: white;
color: black;
transition: transform 0.2s ease, background-color 0.2s ease;
cursor: pointer;
}
.card.red { color: red; }
.card.selected { background-color: lightblue; }
.card.hidden {
background-color: gray;
color: gray;
border: 2px dashed #fff;
cursor: default;
}
/* ボタン共通 */
button {
padding: 10px 20px;
font-size: 16px;
font-weight: bold;
color: white;
background-color: #ff5733;
border: none;
border-radius: 5px;
cursor: pointer;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
transition: background-color 0.2s ease, transform 0.2s ease;
margin: 0 5px;
}
button:hover:not(:disabled) {
background-color: #ff2e00;
transform: scale(1.1);
}
/* 無効時グレーアウト */
button:disabled {
background-color: grey !important;
cursor: not-allowed;
opacity: 0.6;
transform: none !important;
}
/* リセットボタン横並び */
#resetButton {
display: none;
margin-left: 10px;
}
/* 結果表示 */
#result {
font-size: 24px;
margin-top: 20px;
padding: 10px 20px;
background: rgba(0, 0, 0, 0.6);
display: inline-block;
border-radius: 5px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.7);
animation: fadeIn 1s ease;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
</style>
</head>
<body>
<!-- タイトル -->
<h1>🃏 ポーカー対戦ゲーム 🃏</h1>
<!-- プレイヤー手札 -->
<div>
<h2>🧑 プレイヤーの手札 🧑</h2>
<div class="cards" id="playerCards"></div>
</div>
<!-- コンピュータ手札 -->
<div>
<h2>💻 コンピューターの手札 💻</h2>
<div class="cards" id="computerCards"></div>
</div>
<!-- 操作用ボタン -->
<div>
<button id="dealButton" onclick="playGame()">🃏 ゲーム開始</button>
<button id="exchangeButton" onclick="exchangeCards()" disabled>♻️ カード交換</button>
<button id="resultButton" onclick="finalResult()" disabled>🔍 結果を見る</button>
<button id="resetButton" onclick="resetGame()">🔄 ゲームをリセット</button>
</div>
<!-- 結果表示領域 -->
<p id="result"></p>
<script>
const suits = ['♠','♥','♦','♣'];
const values = ['2','3','4','5','6','7','8','9','10','J','Q','K','A'];
const handRanks = {
'ロイヤルストレートフラッシュ':10,'ストレートフラッシュ':9,'フォーカード':8,
'フルハウス':7,'フラッシュ':6,'ストレート':5,'スリーカード':4,
'ツーペア':3,'ワンペア':2,'ハイカード':1
};
let deck = [], playerHand = [], computerHand = [];
let exchangeAllowed = true;
function getDeck(){
const d = [];
for(const s of suits) for(const v of values) d.push({value:v,suit:s});
return d;
}
function shuffle(d){
for(let i=d.length-1;i>0;i--){
const j=Math.floor(Math.random()*(i+1));
[d[i],d[j]]=[d[j],d[i]];
}
return d;
}
function dealCards(d){ return d.splice(0,5); }
function displayCards(hand, id, selectable=false, hidden=false){
const c = document.getElementById(id);
c.innerHTML = '';
hand.forEach((card,i) => {
const div=document.createElement('div');
div.className='card';
div.textContent=hidden?'🂠':`${card.value}${card.suit}`;
if(card.suit==='♥'||card.suit==='♦') div.classList.add('red');
if(hidden) div.classList.add('hidden');
if(selectable) div.onclick=() => div.classList.toggle('selected');
c.appendChild(div);
});
}
function playGame(){
deck = shuffle(getDeck());
playerHand = dealCards(deck);
computerHand = dealCards(deck);
displayCards(playerHand,'playerCards',true,false);
displayCards(computerHand,'computerCards',false,true);
document.getElementById('dealButton').disabled = true;
document.getElementById('exchangeButton').disabled = false;
document.getElementById('resultButton').disabled = false;
document.getElementById('resetButton').style.display = 'none';
document.getElementById('result').textContent = '';
exchangeAllowed = true;
}
function exchangeCards(){
if(!exchangeAllowed) return;
const selected = [];
document.querySelectorAll('#playerCards .card').forEach((div,i)=>{
if(div.classList.contains('selected')) selected.push(i);
});
selected.forEach(i => playerHand[i] = deck.pop());
displayCards(playerHand,'playerCards',false,false);
document.getElementById('exchangeButton').disabled = true;
exchangeAllowed = false;
}
function getHandRank(hand){
const suitsInHand = hand.map(c=>c.suit);
const vals = hand.map(c=>c.value);
const counts = {};
vals.forEach(v=>counts[v]=(counts[v]||0)+1);
const countVals = Object.values(counts).sort((a,b)=>b-a);
const idxs = [...new Set(vals)].map(v=>values.indexOf(v)).sort((a,b)=>a-b);
const isFlush = suitsInHand.every(s=>s===suitsInHand[0]);
const isStraight = idxs.length===5 && idxs[4]-idxs[0]===4;
const isRoyal = isStraight && idxs[0]===values.indexOf('10');
if(isFlush&&isRoyal) return 'ロイヤルストレートフラッシュ';
if(isFlush&&isStraight) return 'ストレートフラッシュ';
if(countVals[0]===4) return 'フォーカード';
if(countVals[0]===3&&countVals[1]===2) return 'フルハウス';
if(isFlush) return 'フラッシュ';
if(isStraight) return 'ストレート';
if(countVals[0]===3) return 'スリーカード';
if(countVals.filter(c=>c===2).length===2) return 'ツーペア';
if(countVals[0]===2) return 'ワンペア';
return 'ハイカード';
}
function finalResult(){
const pR = getHandRank(playerHand);
const cR = getHandRank(computerHand);
displayCards(computerHand,'computerCards',false,false);
const resElm = document.getElementById('result');
resElm.innerHTML = `🧑 プレイヤー:<strong>${pR}</strong> vs 💻 コンピューター:<strong>${cR}</strong><br>`;
const pS = handRanks[pR], cS = handRanks[cR];
if(pS>cS) {
resElm.innerHTML += '<span style="color:lightgreen;font-size:1.5em;">🎉 プレイヤーの勝ち! 🎉</span>';
} else if(pS<cS) {
resElm.innerHTML += '<span style="color:red;font-size:1.5em;">💔 コンピューターの勝ち! 💔</span>';
} else {
resElm.innerHTML += '<span style="color:yellow;font-size:1.5em;">🤝 引き分け! 🤝</span>';
}
document.getElementById('dealButton').disabled = true;
document.getElementById('exchangeButton').disabled = true;
document.getElementById('resultButton').disabled = true;
document.getElementById('resetButton').style.display = 'inline-block';
}
function resetGame(){
document.getElementById('dealButton').disabled = false;
document.getElementById('exchangeButton').disabled = true;
document.getElementById('resultButton').disabled = true;
document.getElementById('resetButton').style.display = 'none';
document.getElementById('playerCards').innerHTML = '';
document.getElementById('computerCards').innerHTML = '';
document.getElementById('result').textContent = '';
}
</script>
</body>
</html>
プログラムのアルゴリズムの流れ
ステップ | 主な関数・命令 | 処理内容 |
---|---|---|
1. デッキ生成・シャッフル | getDeck() → shuffle() | 52枚のトランプを配列化し、Fisher–Yatesでシャッフル |
2. ゲーム開始 | playGame() | デッキから5枚ずつ配り(dealCards() )、手札を描画(displayCards() ) |
3. カード交換 | exchangeCards() | 選択済みカードを検出し、山札から同数を引いて更新 |
4. 役判定 | getHandRank() | 出現回数・絵柄・連番を判定し、役名(ストレートなど)を返す。 |
5. 結果表示 | finalResult() | コンピュータ手札を開示&再描画、両者の役を比較して勝敗を表示 |
6. リセット | resetGame() | UIを初期化し、再度ゲーム開始可能な状態に戻す。 |
splice
で配列からカードを取り出し、pop
で山札から末尾のカードを1枚ずつ引き、querySelectorAll
やdocument.createElement
でカード要素を動的に生成し、classList.toggle
/add
/contains
で選択状態や色付けを制御しています。
関数の詳細
関数名 | 機能 |
---|---|
getDeck() | 4種の絵柄 × 13種の数値を組み合わせ、トランプ52枚のオブジェクト配列を生成 |
shuffle(d) | Fisher–Yatesアルゴリズムで配列をランダムに並び替え |
dealCards(d) | デッキの先頭5枚を手札として取り出し、デッキから削除 |
displayCards() | 指定された要素IDに、手札または裏向きカードを .card 要素として描画 |
playGame() | ゲーム開始時の一連の処理:デッキ生成・シャッフル・配札・UIボタン状態切替 |
exchangeCards() | プレイヤーが選択したカードを山札から補充し、手札を再描画 |
getHandRank() | 手札を分析し、ペア数・連続性・フラッシュ判定の結果から最適な役名を返却 |
finalResult() | コンピュータ手札を表向きにし、手役を比較して勝敗/引き分けを結果欄に表示 |
resetGame() | 手札表示と結果欄、ボタン状態を初期化して再度プレイ可能な状態に戻す |
このゲームの改造のポイント
- 交換回数制限のカスタマイズ:交換を1回から最大2回に増やす、あるいは交換回数をベット制にする。
- ベット&チップ機能:ポーカーらしく賭け金・チップを導入し、勝敗でチップの増減を行う。
- 複数プレイヤー対応:観戦モードや3~4人対戦モードに拡張。
- AIの強化:コンピュータの交換ロジックを、確率計算や期待値評価に基づく戦略的判断にアップグレード。
- ブラウザ間対戦:WebSocket を使ったリアルタイムオンライン対戦対応。
- ビジュアル演出・効果音:カードめくりアニメ、勝敗サウンド、背景エフェクトで臨場感アップ。
- モバイル最適化:タッチ操作でカード選択・交換、レスポンシブデザイン対応。
これらを組み合わせて、より本格的なポーカーゲーム体験を実現してみてください!