
【ゲーム】JavaScript:11 ブラックジャック
「🃏 ブラックジャック 🃏 」は、プレイヤー(あなた)とディーラー(コンピュータ)がそれぞれ最初に2枚ずつカードを受け取り、合計点が21を超えないように“ヒット(追加でカードを引く)”や“スタンド(ここで手を止める)”を選択して競うカードゲームです。目標は、ディーラーを上回る合計点(ただし21以下)を作ること。
遊び方と操作方法
- 「🎲 ゲーム開始」を押すと、プレイヤー/ディーラーに2枚ずつ配牌され、ディーラーの1枚目は裏向きで表示されます。
- 「💥 ヒット」を押すとプレイヤーは山札から1枚カードを引きます。合計が21を超えればバスト(敗北)となります。
- 「✋ スタンド」を押すとプレイヤーのターン終了。ディーラーは合計17点未満なら自動でカードを引き続け、17以上で止まります。
- 両者が止まったら点数を比較し、21を超えなかったほうが勝利。引き分けもあります。
- 最後に「🔄 リセット」で初期状態に戻り、何度でもプレイ可能です。
ルール
- 数字カードは数字通り、J/Q/Kは10点、Aは1点または11点として自動判定。
- プレイヤーが21を超えた時点でバスト(即敗北)。
- スタンド後のディーラーは合計17点以上になるまでヒット。
- 両者とも21以下なら点数の高いほうが勝利、同点は引き分け。
🎮ゲームプレイ
以下のリンク先から実際にプレイできます。
11 ブラックジャック
素材のダウンロード
以下のリンクから使用する素材をダウンロードできます。
| blackjack_bg.png |
|---|
![]() |
ゲーム画面イメージ

プログラム全文(blackjack.html)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>🃏 ブラックジャック 🃏</title>
<style>
/* --- 全体スタイル --- */
body {
margin: 0;
padding: 0;
font-family: 'Arial', sans-serif;
text-align: center;
/* 背景画像を blackjack_bg.png に変更 */
background: url('blackjack_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;
margin: 20px 0;
text-shadow: 2px 2px 4px rgba(0,0,0,0.7);
}
h1 { font-size: 2.5em; }
h2 { font-size: 1.8em; }
/* カード表示コンテナ */
.cards {
display: flex;
justify-content: center;
margin: 10px;
}
/* カード1枚分 */
.card {
width: 80px;
height: 120px;
margin: 5px;
border-radius: 10px;
background-color: white;
color: black;
font-size: 20px;
line-height: 120px;
font-weight: bold;
text-align: center;
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
}
.card.red { color: red; }
.card.hidden {
background-color: gray;
color: gray;
border: 2px dashed #fff;
}
/* ボタン */
button {
padding: 10px 20px;
margin: 5px;
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, transform 0.2s;
}
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;
}
/* 結果表示 */
#message {
display: inline-block;
margin: 20px;
padding: 10px 20px;
background: rgba(0,0,0,0.6);
border-radius: 5px;
font-size: 1.2em;
text-shadow: 2px 2px 4px rgba(0,0,0,0.7);
min-width: 200px;
}
</style>
</head>
<body>
<!-- タイトル -->
<h1>🃏 ブラックジャック 🃏</h1>
<!-- プレイヤー -->
<div>
<h2>🧑 プレイヤー</h2>
<div class="cards" id="playerCards"></div>
<p id="playerScore"></p>
</div>
<!-- ディーラー -->
<div>
<h2>💼 ディーラー</h2>
<div class="cards" id="dealerCards"></div>
<p id="dealerScore"></p>
</div>
<!-- 操作用ボタン -->
<div>
<button id="dealBtn" onclick="deal()">🎲 ゲーム開始</button>
<button id="hitBtn" onclick="hit()" disabled>💥 ヒット</button>
<button id="standBtn" onclick="stand()" disabled>✋ スタンド</button>
<button id="resetBtn" onclick="reset()" disabled>🔄 リセット</button>
</div>
<!-- メッセージ表示 -->
<div id="message">ゲーム開始をクリックしてください</div>
<script>
// --- 定数・変数 ---
const suits = ['♠','♥','♦','♣'];
const values = ['2','3','4','5','6','7','8','9','10','J','Q','K','A'];
let deck = [], playerHand = [], dealerHand = [];
// --- デッキ生成 & シャッフル ---
function createDeck() {
const d = [];
for (let s of suits) {
for (let v of values) {
d.push({suit: s, value: v});
}
}
return shuffle(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 displayHand(hand, containerId, hideFirst=false) {
const container = document.getElementById(containerId);
container.innerHTML = '';
hand.forEach((card, idx) => {
const div = document.createElement('div');
div.className = 'card';
if (hideFirst && idx === 0) {
div.classList.add('hidden');
div.textContent = '🂠';
} else {
div.textContent = `${card.value}${card.suit}`;
if (card.suit === '♥' || card.suit === '♦') {
div.classList.add('red');
}
}
container.appendChild(div);
});
document.getElementById(containerId.replace('Cards','Score'))
.textContent = hideFirst
? '?'
: `合計:${calculateValue(hand)}`;
}
// --- 合計点計算 (Aは1または11) ---
function calculateValue(hand) {
let sum = 0, aces = 0;
hand.forEach(c => {
if (c.value === 'A') { sum += 11; aces += 1; }
else if (['K','Q','J'].includes(c.value)) sum += 10;
else sum += parseInt(c.value);
});
while (sum > 21 && aces > 0) {
sum -= 10;
aces--;
}
return sum;
}
// --- ゲーム開始 ---
function deal() {
deck = createDeck();
playerHand = [deck.pop(), deck.pop()];
dealerHand = [deck.pop(), deck.pop()];
displayHand(playerHand, 'playerCards');
displayHand(dealerHand, 'dealerCards', true);
document.getElementById('dealBtn').disabled = true;
document.getElementById('hitBtn').disabled = false;
document.getElementById('standBtn').disabled = false;
document.getElementById('message').textContent = 'ヒットかスタンドを選択';
}
// --- ヒット ---
function hit() {
playerHand.push(deck.pop());
displayHand(playerHand, 'playerCards');
if (calculateValue(playerHand) > 21) {
endGame();
}
}
// --- スタンド ---
function stand() {
document.getElementById('hitBtn').disabled = true;
document.getElementById('standBtn').disabled = true;
while (calculateValue(dealerHand) < 17) {
dealerHand.push(deck.pop());
}
endGame();
}
// --- ゲーム終了判定 & 表示 ---
function endGame() {
displayHand(dealerHand, 'dealerCards', false);
const pTotal = calculateValue(playerHand);
const dTotal = calculateValue(dealerHand);
let result = '';
if (pTotal > 21) result = '💔 プレイヤーバスト!あなたの負け';
else if (dTotal > 21) result = '🎉 ディーラーバスト!あなたの勝ち';
else if (pTotal > dTotal) result = '🎉 あなたの勝ち!';
else if (pTotal < dTotal) result = '💔 あなたの負け…';
else result = '🤝 引き分け!';
document.getElementById('message').textContent = result;
document.getElementById('hitBtn').disabled = true;
document.getElementById('standBtn').disabled = true;
document.getElementById('resetBtn').disabled = false;
}
// --- リセット ---
function reset() {
playerHand = [];
dealerHand = [];
document.getElementById('playerCards').innerHTML = '';
document.getElementById('dealerCards').innerHTML = '';
document.getElementById('playerScore').textContent = '';
document.getElementById('dealerScore').textContent = '';
document.getElementById('dealBtn').disabled = false;
document.getElementById('hitBtn').disabled = true;
document.getElementById('standBtn').disabled = true;
document.getElementById('resetBtn').disabled = true;
document.getElementById('message').textContent = 'ゲーム開始をクリックしてください';
}
</script>
</body>
</html>アルゴリズムの流れ
| ステップ | 関数/命令 | 内容 |
|---|---|---|
| デッキ生成・シャッフル | createDeck() → shuffle() | 52 枚のカードを生成し、Fisher–Yates アルゴリズムでシャッフル |
| 配牌 | deal() | プレイヤー・ディーラーにそれぞれ2枚ずつ配り、UI を更新 |
| 合計点算出 | calculateValue(hand) | A を 11 または 1 として最適変換し、合計点を返却 |
| 手札表示 | displayHand() | カードを <div> 要素として描画し、ディーラーの1枚目は裏向き表示 |
| プレイヤーヒット | hit() | プレイヤーの手札に1枚追加、バスト判定 |
| プレイヤースタンド | stand() | ディーラーが 17 未満なら自動ヒット、終了判定 |
| 終了判定・結果表示 | endGame() | 両者の合計を比較、勝敗メッセージを表示 |
| リセット | reset() | 手札・UI を初期状態に戻し、再度プレイ可能に |
関数の詳細
| 関数名 | 機能 |
|---|---|
createDeck() | 4つの絵柄 × 13 の値を組み合わせて 52 枚のデッキ配列を生成 |
shuffle(d) | Fisher–Yates で配列 d をランダムに並び替え。 |
displayHand(hand,id,hideFirst) | 手札をカード要素として描画。hideFirst=true でディーラー1枚目を裏向きに |
calculateValue(hand) | J/Q/K→10、A→11→1 と最適に調整しながら点数を計算 |
deal() | デッキ生成→配牌→UI 更新→ボタン有効化 |
hit() | プレイヤーが山札から1枚追加→UI 更新→バスト判定 |
stand() | ヒット/スタンド操作を無効化→ディーラーロジック(17 未満でヒット)→終了判定 |
endGame() | ディーラーの裏向きカードを表示→合計比較→メッセージ表示→操作ボタン状態更新 |
reset() | すべての手札・スコア・メッセージをクリア→ボタン状態を初期化 |
このゲームの改造のポイント
- ベット&チップ機能:プレイヤーがチップを賭け、勝敗でチップの増減を管理。
- ブラックジャック判定:「A+10 点コンビ」時の自動ブラックジャック判定と報酬倍率を追加。
- 複数デッキ対応:本場同様に複数デッキ(6 デッキなど)を扱うロジックを導入。
- サイドベット:ペア/赤黒/スート一致などへのオプションベットを実装。
- AI 強化:ディーラーではなく、基礎戦略表に基づく選択(ヒット/スタンド/ダブルダウン/スプリット)を導入。
- UI 演出:カードめくりアニメ、チップアニメーション、効果音、勝利エフェクトなどを追加。
- オンライン対戦:WebSocket を使った複数人同時対戦やリモート対戦モード。
ぜひこの基本実装をベースに、自分好みのルールや演出を盛り込んで、より本格的なブラックジャック体験を作り込んでみてください!

