
【ゲーム】JavaScript:25 数当てゲーム(Hit & Blow)
「数当てゲーム(Hit & Blow)」は、プレイヤーが4桁のランダムな数字(重複なし)を入力し、ヒット&ブローの情報をもとに正解の数字と並び順を推理して当てるパズルゲームです。ヒットは「数字も位置も一致」、ブローは「数字のみ一致」を示し、「Hitが4」になったらクリアとなります。
遊び方と操作方法
- タイトル画面の「スタート 🚀」ボタンをクリック
- ゲーム画面で4桁の数字(例:1234)を入力欄に入力
- 「判定 ✔️」ボタン、または Enter キーで結果を確認
- フィードバック欄に「X Hit / Y Blow」が表示されるので、次の推理に活用
- 試行を繰り返し、Hitが4になったら「ゲームクリア 🎉」画面へ
ルール
- 正解数字は重複なしの4桁ランダム(0000〜9999のうち10P4通り)
- Hit:同じ桁に同じ数字がある数
- Blow:異なる桁だが数字が含まれている数
- Hitが4になると正解
- 試行回数は右下に表示/最大99回(任意設定)
🎮ゲームプレイ
以下のリンク先から実際にプレイできます。
素材のダウンロード
以下のリンクから使用する素材をダウンロードできます。
hit_blow_title.png | hit_blow_bg.png |
---|---|
![]() | ![]() |
ゲーム画面イメージ

プログラム全文(hit_blow.html)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>🔢 数当てゲーム (Hit & Blow) 🔢</title>
<style>
/* ===== 全体背景設定 ===== */
body {
margin: 0;
padding: 0;
font-family: 'Arial', sans-serif;
/* 背景画像を固定で全面に表示 */
background: url('hit_blow_bg.png') no-repeat center center fixed;
background-size: cover;
}
/* ===== 中央オーバーレイ共通スタイル ===== */
.overlay {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
background-color: rgba(255, 255, 255, 0.9);
padding: 20px;
border-radius: 10px;
text-align: center;
width: 90%; max-width: 500px;
}
/* 非表示用クラス */
.hidden {
display: none;
}
/* タイトル画像サイズ調整 */
.title-image {
display: block;
margin: 0 auto 10px;
max-width: 80%;
height: auto;
}
/* ===== 汎用ボタン(スタート/判定/リスタート) ===== */
.btn {
display: inline-block;
padding: 12px 24px;
font-size: 18px;
font-weight: bold;
margin: 15px 5px 0;
cursor: pointer;
border: 2px solid #e0a800;
border-radius: 8px;
background-color: #ffc107; /* 高コントラスト黄色 */
color: #000;
box-shadow: 0 4px 6px rgba(0,0,0,0.2);
transition: background-color 0.2s, transform 0.1s;
}
.btn:hover {
background-color: #e0a800;
transform: translateY(-2px);
}
.btn:active {
transform: translateY(0);
box-shadow: 0 2px 4px rgba(0,0,0,0.2);
}
/* ===== 入力フィールドスタイル ===== */
#guess-input {
font-size: 18px;
padding: 8px;
width: 140px;
text-align: center;
border: 2px solid #343a40;
border-radius: 5px;
}
/* ===== フィードバックメッセージ ===== */
.message {
margin-top: 15px;
padding: 10px;
background-color: rgba(0, 0, 0, 0.7);
color: #fff;
border-radius: 5px;
min-height: 1.5em;
}
/* ===== 試行回数表示 ===== */
.attempt-display {
margin-top: 10px;
font-size: 18px;
}
</style>
</head>
<body>
<!-- ===== タイトル画面 ===== -->
<div id="title-screen" class="overlay">
<img src="hit_blow_title.png" alt="数当てゲームタイトル" class="title-image">
<h1>🔢 数当てゲーム (Hit & Blow) 🔢</h1>
<p>遊び方:4桁のランダムな数字を推理して当ててください。<br>
同じ数字は使われません。</p>
<p>📜 ルール 📜</p>
<ul style="text-align:left;">
<li>Hit:数字と位置が合っている数</li>
<li>Blow:数字だけ合っている数</li>
<li>Hitが4になったらクリア!</li>
</ul>
<button id="start-btn" class="btn">スタート 🚀</button>
</div>
<!-- ===== ゲーム画面 ===== -->
<div id="game-screen" class="overlay hidden">
<h2>推理して数字を入力</h2>
<!-- ユーザー入力 -->
<input type="text" id="guess-input" maxlength="4" placeholder="例: 1234">
<button id="submit-btn" class="btn">判定 ✔️</button>
<!-- フィードバック表示 -->
<div id="feedback" class="message"></div>
<!-- 試行回数表示 -->
<div class="attempt-display">試行回数: <span id="attempt-count">0</span> 回</div>
</div>
<!-- ===== 終了画面 ===== -->
<div id="end-screen" class="overlay hidden">
<h2>ゲームクリア 🎉</h2>
<p id="final-message">正解!試行回数は 0 回でした!</p>
<button id="restart-btn" class="btn">タイトルに戻る 🔄</button>
</div>
<script>
// ================================================
// 定数設定
// ================================================
const DIGITS = 4; // 桁数
const MAX_ATTEMPTS = 99; // 最大試行回数(任意)
// ================================================
// ゲーム状態用変数
// ================================================
let answer = []; // 正解配列
let attempts = 0; // 試行回数
// ================================================
// DOM要素取得
// ================================================
const titleScreen = document.getElementById('title-screen');
const gameScreen = document.getElementById('game-screen');
const endScreen = document.getElementById('end-screen');
const startBtn = document.getElementById('start-btn');
const submitBtn = document.getElementById('submit-btn');
const restartBtn = document.getElementById('restart-btn');
const guessInput = document.getElementById('guess-input');
const feedbackDiv = document.getElementById('feedback');
const attemptSpan = document.getElementById('attempt-count');
const finalMessage = document.getElementById('final-message');
/**
* タイトル画面表示
*/
function showTitle() {
titleScreen.classList.remove('hidden');
gameScreen.classList.add('hidden');
endScreen.classList.add('hidden');
}
/**
* ゲーム開始処理
* - 正解をランダム生成
* - 画面切り替え
* - 変数初期化
*/
function startGame() {
// 正解を生成
answer = generateAnswer();
// 試行回数リセット
attempts = 0;
attemptSpan.textContent = attempts;
// フィードバッククリア
feedbackDiv.textContent = '';
// 入力欄クリア
guessInput.value = '';
// 画面切り替え
titleScreen.classList.add('hidden');
endScreen.classList.add('hidden');
gameScreen.classList.remove('hidden');
// フォーカスを入力欄へ
guessInput.focus();
}
/**
* 正解となるランダム4桁の配列を生成
* @returns {string[]} 4桁の文字列配列
*/
function generateAnswer() {
const nums = [...Array(10).keys()]; // 0~9の配列
const result = [];
// 重複なくDIGITS個取得
for (let i = 0; i < DIGITS; i++) {
const idx = Math.floor(Math.random() * nums.length);
result.push(String(nums.splice(idx, 1)[0]));
}
return result;
}
/**
* ユーザーの入力をチェックし、Hit & Blowを判定
*/
function handleGuess() {
const guess = guessInput.value.trim();
// 入力バリデーション:4桁かつ数字かつ重複なし
if (!/^\d{4}$/.test(guess) || new Set(guess).size !== DIGITS) {
feedbackDiv.textContent = '4桁の重複しない数字を入力してください。';
return;
}
// 試行回数を増やす
attempts++;
attemptSpan.textContent = attempts;
// Hit & Blow 判定
let hit = 0, blow = 0;
for (let i = 0; i < DIGITS; i++) {
if (guess[i] === answer[i]) {
hit++;
} else if (answer.includes(guess[i])) {
blow++;
}
}
// フィードバック表示
feedbackDiv.textContent = `${hit} Hit / ${blow} Blow`;
// 正解判定
if (hit === DIGITS) {
endGame();
} else {
// 次の入力に備えてクリア&フォーカス
guessInput.value = '';
guessInput.focus();
}
}
/**
* ゲーム終了処理
* - 終了画面へ切り替え
* - 最終メッセージ表示
*/
function endGame() {
gameScreen.classList.add('hidden');
endScreen.classList.remove('hidden');
finalMessage.textContent = `正解!試行回数は ${attempts} 回でした!`;
}
// ================================================
// イベントリスナー設定
// ================================================
document.addEventListener('DOMContentLoaded', () => {
// スタートボタン
startBtn.addEventListener('click', startGame);
// 判定ボタン
submitBtn.addEventListener('click', handleGuess);
// Enterキーでも判定
guessInput.addEventListener('keyup', e => {
if (e.key === 'Enter') handleGuess();
});
// リスタートボタン
restartBtn.addEventListener('click', showTitle);
// 最初はタイトル画面
showTitle();
});
</script>
</body>
</html>
アルゴリズムの流れ
ステップ | 処理内容 | 主な関数/命令 |
---|---|---|
1. タイトル表示 | タイトル画面を表示、他画面を隠す | showTitle() |
2. ゲーム開始 | generateAnswer() で解答生成、試行回数・フィードバック初期化、画面切替 | startGame() |
3. 正解生成 | 0〜9の配列から重複なく4つをランダム抽出 | generateAnswer() |
4. 推理入力&判定 | 入力バリデーション → Hit/Blow 計算 → フィードバック表示 | handleGuess() |
5. 終了判定 | Hitが4か、Enter/判定ボタンで判定後に endGame() へ分岐 | handleGuess() → endGame() |
6. 結果表示 | ゲーム画面を隠し、終了画面を表示、試行回数をメッセージに反映 | endGame() |
関数・命令の解説
関数名/命令 | 説明 |
---|---|
showTitle() | 各画面の .hidden クラスを操作し、タイトル画面を表示 |
startGame() | 正解生成・試行回数リセット・画面切替・入力欄フォーカス |
generateAnswer() | 0〜9の数値配列から重複なしで4つの要素をランダムに抽出し文字列配列として返却 |
handleGuess() | 入力検証・試行回数インクリメント・Hit/Blow 計算・フィードバック表示・終了判定 |
endGame() | 結果画面への画面切替と最終メッセージ設定 |
guessInput.addEventListener('keyup', …) | Enter キー押下で handleGuess() を呼び出し、操作性を向上 |
改造のポイント
- 桁数変更:
DIGITS
定数を変更すると任意の桁数に対応可能。 - 重複ルールの緩和:
generateAnswer()
で重複を許す、あるいは特定の数字を除外するロジックへカスタマイズ。 - ヒント機能の追加:一定回数ごとに「〇〇は含まれている/いない」などのヒントを表示。
- 最大試行数制限:
MAX_ATTEMPTS
を超えたら自動でゲームオーバーにする機能。 - UI強化:正誤時にHitは緑、Blowは黄色など色分け表示、アニメーションを追加。
- タイムチャレンジモード:制限時間を設け、時間内にクリアできるか競うモードを追加。
アドバイス:ユーザーの推理を助けるヒント機能(例:特定の数字の有無や位置範囲の絞り込み)を追加すると初心者にも優しいゲームになります。また、クリアタイムや最少試行数を
localStorage
に保存して、ランキング表示を実装するとリプレイ性が向上します!